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);
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, u_int32_t *, NFSX_UNSIGNED);
1710 if (compare) {
1711 if (!(*retcmpp)) {
1712 if (*tl != newnfs_false)
1713 *retcmpp = NFSERR_NOTSAME;
1714 }
1715 } else if (pc != NULL) {
1716 pc->pc_caseinsensitive =
1717 fxdr_unsigned(u_int32_t, *tl);
1718 }
1719 attrsum += NFSX_UNSIGNED;
1720 break;
1721 case NFSATTRBIT_CASEPRESERVING:
1722 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1723 if (compare) {
1724 if (!(*retcmpp)) {
1725 if (*tl != newnfs_true)
1726 *retcmpp = NFSERR_NOTSAME;
1727 }
1728 } else if (pc != NULL) {
1729 pc->pc_casepreserving =
1730 fxdr_unsigned(u_int32_t, *tl);
1731 }
1732 attrsum += NFSX_UNSIGNED;
1733 break;
1734 case NFSATTRBIT_CHOWNRESTRICTED:
1735 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1736 if (compare) {
1737 if (!(*retcmpp)) {
1738 if (*tl != newnfs_true)
1739 *retcmpp = NFSERR_NOTSAME;
1740 }
1741 } else if (pc != NULL) {
1742 pc->pc_chownrestricted =
1743 fxdr_unsigned(u_int32_t, *tl);
1744 }
1745 attrsum += NFSX_UNSIGNED;
1746 break;
1747 case NFSATTRBIT_FILEHANDLE:
1748 error = nfsm_getfh(nd, &tnfhp);
1749 if (error)
1750 goto nfsmout;
1751 tfhsize = tnfhp->nfh_len;
1752 if (compare) {
1753 if (tfhsize > NFSX_MYFH)
1754 tfhsize = NFSX_MYFH;
1755 if (!(*retcmpp) &&
1756 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1757 fhp, fhsize))
1758 *retcmpp = NFSERR_NOTSAME;
1759 free(tnfhp, M_NFSFH);
1760 } else if (nfhpp != NULL) {
1761 *nfhpp = tnfhp;
1762 } else {
1763 free(tnfhp, M_NFSFH);
1764 }
1765 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1766 break;
1767 case NFSATTRBIT_FILEID:
1768 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1769 thyp = fxdr_hyper(tl);
1770 if (compare) {
1771 if (!(*retcmpp)) {
1772 if (nap->na_fileid != thyp)
1773 *retcmpp = NFSERR_NOTSAME;
1774 }
1775 } else if (nap != NULL)
1776 nap->na_fileid = thyp;
1777 attrsum += NFSX_HYPER;
1778 break;
1779 case NFSATTRBIT_FILESAVAIL:
1780 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1781 if (compare) {
1782 uquad = nfsv4_filesavail(sbp, vp->v_mount);
1783 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1784 *retcmpp = NFSERR_NOTSAME;
1785 } else if (sfp != NULL) {
1786 sfp->sf_afiles = fxdr_hyper(tl);
1787 }
1788 attrsum += NFSX_HYPER;
1789 break;
1790 case NFSATTRBIT_FILESFREE:
1791 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1792 if (compare) {
1793 uquad = (uint64_t)sbp->f_ffree;
1794 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1795 *retcmpp = NFSERR_NOTSAME;
1796 } else if (sfp != NULL) {
1797 sfp->sf_ffiles = fxdr_hyper(tl);
1798 }
1799 attrsum += NFSX_HYPER;
1800 break;
1801 case NFSATTRBIT_FILESTOTAL:
1802 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1803 if (compare) {
1804 uquad = sbp->f_files;
1805 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1806 *retcmpp = NFSERR_NOTSAME;
1807 } else if (sfp != NULL) {
1808 sfp->sf_tfiles = fxdr_hyper(tl);
1809 }
1810 attrsum += NFSX_HYPER;
1811 break;
1812 case NFSATTRBIT_FSLOCATIONS:
1813 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1814 if (error)
1815 goto nfsmout;
1816 attrsum += l;
1817 if (compare && !(*retcmpp)) {
1818 refp = nfsv4root_getreferral(vp, NULL, 0);
1819 if (refp != NULL) {
1820 if (cp == NULL || cp2 == NULL ||
1821 strcmp(cp, "/") ||
1822 strcmp(cp2, refp->nfr_srvlist))
1823 *retcmpp = NFSERR_NOTSAME;
1824 } else if (m == 0) {
1825 *retcmpp = NFSERR_NOTSAME;
1826 }
1827 }
1828 if (cp != NULL)
1829 free(cp, M_NFSSTRING);
1830 if (cp2 != NULL)
1831 free(cp2, M_NFSSTRING);
1832 break;
1833 case NFSATTRBIT_HIDDEN:
1834 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1835 if (compare) {
1836 if (!(*retcmpp) && ((*tl == newnfs_true &&
1837 (nap->na_flags & UF_HIDDEN) == 0) ||
1838 (*tl == newnfs_false &&
1839 (nap->na_flags & UF_HIDDEN) != 0)))
1840 *retcmpp = NFSERR_NOTSAME;
1841 } else if (nap != NULL) {
1842 if (*tl == newnfs_true)
1843 nap->na_flags |= UF_HIDDEN;
1844 }
1845 attrsum += NFSX_UNSIGNED;
1846 break;
1847 case NFSATTRBIT_HOMOGENEOUS:
1848 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1849 if (compare) {
1850 if (!(*retcmpp)) {
1851 if (fsp->fs_properties &
1852 NFSV3_FSFHOMOGENEOUS) {
1853 if (*tl == newnfs_false)
1854 *retcmpp = NFSERR_NOTSAME;
1855 } else {
1856 if (*tl == newnfs_true)
1857 *retcmpp = NFSERR_NOTSAME;
1858 }
1859 }
1860 } else if (fsp != NULL) {
1861 if (*tl == newnfs_true)
1862 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1863 else
1864 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1865 }
1866 attrsum += NFSX_UNSIGNED;
1867 break;
1868 case NFSATTRBIT_MAXFILESIZE:
1869 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1870 tnfsquad.qval = fxdr_hyper(tl);
1871 if (compare) {
1872 if (!(*retcmpp)) {
1873 tquad = NFSRV_MAXFILESIZE;
1874 if (tquad != tnfsquad.qval)
1875 *retcmpp = NFSERR_NOTSAME;
1876 }
1877 } else if (fsp != NULL) {
1878 fsp->fs_maxfilesize = tnfsquad.qval;
1879 }
1880 attrsum += NFSX_HYPER;
1881 break;
1882 case NFSATTRBIT_MAXLINK:
1883 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1884 if (compare) {
1885 if (!(*retcmpp)) {
1886 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1887 *retcmpp = NFSERR_NOTSAME;
1888 }
1889 } else if (pc != NULL) {
1890 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1891 }
1892 attrsum += NFSX_UNSIGNED;
1893 break;
1894 case NFSATTRBIT_MAXNAME:
1895 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1896 if (compare) {
1897 if (!(*retcmpp)) {
1898 if (fsp->fs_maxname !=
1899 fxdr_unsigned(u_int32_t, *tl))
1900 *retcmpp = NFSERR_NOTSAME;
1901 }
1902 } else {
1903 tuint = fxdr_unsigned(u_int32_t, *tl);
1904 /*
1905 * Some Linux NFSv4 servers report this
1906 * as 0 or 4billion, so I'll set it to
1907 * NFS_MAXNAMLEN. If a server actually creates
1908 * a name longer than NFS_MAXNAMLEN, it will
1909 * get an error back.
1910 */
1911 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1912 tuint = NFS_MAXNAMLEN;
1913 if (fsp != NULL)
1914 fsp->fs_maxname = tuint;
1915 if (pc != NULL)
1916 pc->pc_namemax = tuint;
1917 }
1918 attrsum += NFSX_UNSIGNED;
1919 break;
1920 case NFSATTRBIT_MAXREAD:
1921 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1922 if (compare) {
1923 if (!(*retcmpp)) {
1924 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1925 *(tl + 1)) || *tl != 0)
1926 *retcmpp = NFSERR_NOTSAME;
1927 }
1928 } else if (fsp != NULL) {
1929 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1930 fsp->fs_rtpref = fsp->fs_rtmax;
1931 fsp->fs_dtpref = fsp->fs_rtpref;
1932 }
1933 attrsum += NFSX_HYPER;
1934 break;
1935 case NFSATTRBIT_MAXWRITE:
1936 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1937 if (compare) {
1938 if (!(*retcmpp)) {
1939 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1940 *(tl + 1)) || *tl != 0)
1941 *retcmpp = NFSERR_NOTSAME;
1942 }
1943 } else if (fsp != NULL) {
1944 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1945 fsp->fs_wtpref = fsp->fs_wtmax;
1946 }
1947 attrsum += NFSX_HYPER;
1948 break;
1949 case NFSATTRBIT_MIMETYPE:
1950 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1951 i = fxdr_unsigned(int, *tl);
1952 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1953 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1954 if (error)
1955 goto nfsmout;
1956 if (compare && !(*retcmpp))
1957 *retcmpp = NFSERR_ATTRNOTSUPP;
1958 break;
1959 case NFSATTRBIT_MODE:
1960 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1961 if (compare) {
1962 if (!(*retcmpp)) {
1963 if (nap->na_mode != nfstov_mode(*tl))
1964 *retcmpp = NFSERR_NOTSAME;
1965 }
1966 } else if (nap != NULL) {
1967 nap->na_mode = nfstov_mode(*tl);
1968 }
1969 attrsum += NFSX_UNSIGNED;
1970 break;
1971 case NFSATTRBIT_NOTRUNC:
1972 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1973 if (compare) {
1974 if (!(*retcmpp)) {
1975 if (*tl != newnfs_true)
1976 *retcmpp = NFSERR_NOTSAME;
1977 }
1978 } else if (pc != NULL) {
1979 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1980 }
1981 attrsum += NFSX_UNSIGNED;
1982 break;
1983 case NFSATTRBIT_NUMLINKS:
1984 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1985 tuint = fxdr_unsigned(u_int32_t, *tl);
1986 if (compare) {
1987 if (!(*retcmpp)) {
1988 if ((u_int32_t)nap->na_nlink != tuint)
1989 *retcmpp = NFSERR_NOTSAME;
1990 }
1991 } else if (nap != NULL) {
1992 nap->na_nlink = tuint;
1993 }
1994 attrsum += NFSX_UNSIGNED;
1995 break;
1996 case NFSATTRBIT_OWNER:
1997 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1998 j = fxdr_unsigned(int, *tl);
1999 if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
2000 error = NFSERR_BADXDR;
2001 goto nfsmout;
2002 }
2003 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
2004 if (j > NFSV4_SMALLSTR)
2005 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
2006 else
2007 cp = namestr;
2008 error = nfsrv_mtostr(nd, cp, j);
2009 if (error) {
2010 if (j > NFSV4_SMALLSTR)
2011 free(cp, M_NFSSTRING);
2012 goto nfsmout;
2013 }
2014 if (compare) {
2015 if (!(*retcmpp)) {
2016 if (nfsv4_strtouid(nd, cp, j, &uid) ||
2017 nap->na_uid != uid)
2018 *retcmpp = NFSERR_NOTSAME;
2019 }
2020 } else if (nap != NULL) {
2021 if (nfsv4_strtouid(nd, cp, j, &uid))
2022 nap->na_uid =
2023 NFSD_VNET(nfsrv_defaultuid);
2024 else
2025 nap->na_uid = uid;
2026 }
2027 if (j > NFSV4_SMALLSTR)
2028 free(cp, M_NFSSTRING);
2029 break;
2030 case NFSATTRBIT_OWNERGROUP:
2031 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2032 j = fxdr_unsigned(int, *tl);
2033 if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
2034 error = NFSERR_BADXDR;
2035 goto nfsmout;
2036 }
2037 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
2038 if (j > NFSV4_SMALLSTR)
2039 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
2040 else
2041 cp = namestr;
2042 error = nfsrv_mtostr(nd, cp, j);
2043 if (error) {
2044 if (j > NFSV4_SMALLSTR)
2045 free(cp, M_NFSSTRING);
2046 goto nfsmout;
2047 }
2048 if (compare) {
2049 if (!(*retcmpp)) {
2050 if (nfsv4_strtogid(nd, cp, j, &gid) ||
2051 nap->na_gid != gid)
2052 *retcmpp = NFSERR_NOTSAME;
2053 }
2054 } else if (nap != NULL) {
2055 if (nfsv4_strtogid(nd, cp, j, &gid))
2056 nap->na_gid =
2057 NFSD_VNET(nfsrv_defaultgid);
2058 else
2059 nap->na_gid = gid;
2060 }
2061 if (j > NFSV4_SMALLSTR)
2062 free(cp, M_NFSSTRING);
2063 break;
2064 case NFSATTRBIT_QUOTAHARD:
2065 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2066 if (sbp != NULL) {
2067 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2068 freenum = sbp->f_bfree;
2069 else
2070 freenum = sbp->f_bavail;
2071 #ifdef QUOTA
2072 /*
2073 * ufs_quotactl() insists that the uid argument
2074 * equal p_ruid for non-root quota access, so
2075 * we'll just make sure that's the case.
2076 */
2077 savuid = p->p_cred->p_ruid;
2078 p->p_cred->p_ruid = cred->cr_uid;
2079 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
2080 USRQUOTA), cred->cr_uid, &dqb))
2081 freenum = min(dqb.dqb_bhardlimit, freenum);
2082 p->p_cred->p_ruid = savuid;
2083 #endif /* QUOTA */
2084 uquad = (u_int64_t)freenum;
2085 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
2086 }
2087 if (compare && !(*retcmpp)) {
2088 if (uquad != fxdr_hyper(tl))
2089 *retcmpp = NFSERR_NOTSAME;
2090 }
2091 attrsum += NFSX_HYPER;
2092 break;
2093 case NFSATTRBIT_QUOTASOFT:
2094 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2095 if (sbp != NULL) {
2096 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2097 freenum = sbp->f_bfree;
2098 else
2099 freenum = sbp->f_bavail;
2100 #ifdef QUOTA
2101 /*
2102 * ufs_quotactl() insists that the uid argument
2103 * equal p_ruid for non-root quota access, so
2104 * we'll just make sure that's the case.
2105 */
2106 savuid = p->p_cred->p_ruid;
2107 p->p_cred->p_ruid = cred->cr_uid;
2108 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
2109 USRQUOTA), cred->cr_uid, &dqb))
2110 freenum = min(dqb.dqb_bsoftlimit, freenum);
2111 p->p_cred->p_ruid = savuid;
2112 #endif /* QUOTA */
2113 uquad = (u_int64_t)freenum;
2114 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
2115 }
2116 if (compare && !(*retcmpp)) {
2117 if (uquad != fxdr_hyper(tl))
2118 *retcmpp = NFSERR_NOTSAME;
2119 }
2120 attrsum += NFSX_HYPER;
2121 break;
2122 case NFSATTRBIT_QUOTAUSED:
2123 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2124 if (sbp != NULL) {
2125 freenum = 0;
2126 #ifdef QUOTA
2127 /*
2128 * ufs_quotactl() insists that the uid argument
2129 * equal p_ruid for non-root quota access, so
2130 * we'll just make sure that's the case.
2131 */
2132 savuid = p->p_cred->p_ruid;
2133 p->p_cred->p_ruid = cred->cr_uid;
2134 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
2135 USRQUOTA), cred->cr_uid, &dqb))
2136 freenum = dqb.dqb_curblocks;
2137 p->p_cred->p_ruid = savuid;
2138 #endif /* QUOTA */
2139 uquad = (u_int64_t)freenum;
2140 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
2141 }
2142 if (compare && !(*retcmpp)) {
2143 if (uquad != fxdr_hyper(tl))
2144 *retcmpp = NFSERR_NOTSAME;
2145 }
2146 attrsum += NFSX_HYPER;
2147 break;
2148 case NFSATTRBIT_RAWDEV:
2149 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
2150 j = fxdr_unsigned(int, *tl++);
2151 k = fxdr_unsigned(int, *tl);
2152 if (compare) {
2153 if (!(*retcmpp)) {
2154 if (nap->na_rdev != NFSMAKEDEV(j, k))
2155 *retcmpp = NFSERR_NOTSAME;
2156 }
2157 } else if (nap != NULL) {
2158 nap->na_rdev = NFSMAKEDEV(j, k);
2159 }
2160 attrsum += NFSX_V4SPECDATA;
2161 break;
2162 case NFSATTRBIT_SPACEAVAIL:
2163 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2164 if (compare) {
2165 if (priv_check_cred(cred,
2166 PRIV_VFS_BLOCKRESERVE))
2167 uquad = sbp->f_bfree;
2168 else
2169 uquad = (uint64_t)sbp->f_bavail;
2170 uquad *= sbp->f_bsize;
2171 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2172 *retcmpp = NFSERR_NOTSAME;
2173 } else if (sfp != NULL) {
2174 sfp->sf_abytes = fxdr_hyper(tl);
2175 }
2176 attrsum += NFSX_HYPER;
2177 break;
2178 case NFSATTRBIT_SPACEFREE:
2179 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2180 if (compare) {
2181 uquad = sbp->f_bfree;
2182 uquad *= sbp->f_bsize;
2183 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2184 *retcmpp = NFSERR_NOTSAME;
2185 } else if (sfp != NULL) {
2186 sfp->sf_fbytes = fxdr_hyper(tl);
2187 }
2188 attrsum += NFSX_HYPER;
2189 break;
2190 case NFSATTRBIT_SPACETOTAL:
2191 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2192 if (compare) {
2193 uquad = sbp->f_blocks;
2194 uquad *= sbp->f_bsize;
2195 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2196 *retcmpp = NFSERR_NOTSAME;
2197 } else if (sfp != NULL) {
2198 sfp->sf_tbytes = fxdr_hyper(tl);
2199 }
2200 attrsum += NFSX_HYPER;
2201 break;
2202 case NFSATTRBIT_SPACEUSED:
2203 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2204 thyp = fxdr_hyper(tl);
2205 if (compare) {
2206 if (!(*retcmpp)) {
2207 if ((u_int64_t)nap->na_bytes != thyp)
2208 *retcmpp = NFSERR_NOTSAME;
2209 }
2210 } else if (nap != NULL) {
2211 nap->na_bytes = thyp;
2212 }
2213 attrsum += NFSX_HYPER;
2214 break;
2215 case NFSATTRBIT_SYSTEM:
2216 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2217 if (compare) {
2218 if (!(*retcmpp) && ((*tl == newnfs_true &&
2219 (nap->na_flags & UF_SYSTEM) == 0) ||
2220 (*tl == newnfs_false &&
2221 (nap->na_flags & UF_SYSTEM) != 0)))
2222 *retcmpp = NFSERR_NOTSAME;
2223 } else if (nap != NULL) {
2224 if (*tl == newnfs_true)
2225 nap->na_flags |= UF_SYSTEM;
2226 }
2227 attrsum += NFSX_UNSIGNED;
2228 break;
2229 case NFSATTRBIT_TIMEACCESS:
2230 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2231 fxdr_nfsv4time(tl, &temptime);
2232 if (compare) {
2233 if (!(*retcmpp)) {
2234 if (!NFS_CMPTIME(temptime, nap->na_atime))
2235 *retcmpp = NFSERR_NOTSAME;
2236 }
2237 } else if (nap != NULL) {
2238 nap->na_atime = temptime;
2239 }
2240 attrsum += NFSX_V4TIME;
2241 break;
2242 case NFSATTRBIT_TIMEACCESSSET:
2243 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2244 attrsum += NFSX_UNSIGNED;
2245 i = fxdr_unsigned(int, *tl);
2246 if (i == NFSV4SATTRTIME_TOCLIENT) {
2247 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2248 attrsum += NFSX_V4TIME;
2249 }
2250 if (compare && !(*retcmpp))
2251 *retcmpp = NFSERR_INVAL;
2252 break;
2253 case NFSATTRBIT_TIMEBACKUP:
2254 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2255 if (compare && !(*retcmpp))
2256 *retcmpp = NFSERR_ATTRNOTSUPP;
2257 attrsum += NFSX_V4TIME;
2258 break;
2259 case NFSATTRBIT_TIMECREATE:
2260 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2261 fxdr_nfsv4time(tl, &temptime);
2262 if (compare) {
2263 if (!(*retcmpp)) {
2264 if (!NFS_CMPTIME(temptime, nap->na_btime))
2265 *retcmpp = NFSERR_NOTSAME;
2266 }
2267 } else if (nap != NULL) {
2268 nap->na_btime = temptime;
2269 }
2270 attrsum += NFSX_V4TIME;
2271 break;
2272 case NFSATTRBIT_TIMEDELTA:
2273 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2274 if (fsp != NULL) {
2275 if (compare) {
2276 if (!(*retcmpp)) {
2277 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2278 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2279 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2280 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2281 1000000000) ||
2282 *tl != 0)
2283 *retcmpp = NFSERR_NOTSAME;
2284 }
2285 } else {
2286 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2287 }
2288 }
2289 attrsum += NFSX_V4TIME;
2290 break;
2291 case NFSATTRBIT_TIMEMETADATA:
2292 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2293 fxdr_nfsv4time(tl, &temptime);
2294 if (compare) {
2295 if (!(*retcmpp)) {
2296 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2297 *retcmpp = NFSERR_NOTSAME;
2298 }
2299 } else if (nap != NULL) {
2300 nap->na_ctime = temptime;
2301 }
2302 attrsum += NFSX_V4TIME;
2303 break;
2304 case NFSATTRBIT_TIMEMODIFY:
2305 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2306 fxdr_nfsv4time(tl, &temptime);
2307 if (compare) {
2308 if (!(*retcmpp)) {
2309 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2310 *retcmpp = NFSERR_NOTSAME;
2311 }
2312 } else if (nap != NULL) {
2313 nap->na_mtime = temptime;
2314 }
2315 attrsum += NFSX_V4TIME;
2316 break;
2317 case NFSATTRBIT_TIMEMODIFYSET:
2318 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2319 attrsum += NFSX_UNSIGNED;
2320 i = fxdr_unsigned(int, *tl);
2321 if (i == NFSV4SATTRTIME_TOCLIENT) {
2322 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2323 attrsum += NFSX_V4TIME;
2324 }
2325 if (compare && !(*retcmpp))
2326 *retcmpp = NFSERR_INVAL;
2327 break;
2328 case NFSATTRBIT_MOUNTEDONFILEID:
2329 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2330 thyp = fxdr_hyper(tl);
2331 if (compare) {
2332 if (!(*retcmpp)) {
2333 if (!vp || !nfsrv_atroot(vp, &thyp2))
2334 thyp2 = nap->na_fileid;
2335 if (thyp2 != thyp)
2336 *retcmpp = NFSERR_NOTSAME;
2337 }
2338 } else if (nap != NULL)
2339 nap->na_mntonfileno = thyp;
2340 attrsum += NFSX_HYPER;
2341 break;
2342 case NFSATTRBIT_SUPPATTREXCLCREAT:
2343 retnotsup = 0;
2344 error = nfsrv_getattrbits(nd, &retattrbits,
2345 &cnt, &retnotsup);
2346 if (error)
2347 goto nfsmout;
2348 if (compare && !(*retcmpp)) {
2349 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2350 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2351 NFSCLRBIT_ATTRBIT(&checkattrbits,
2352 NFSATTRBIT_TIMEACCESSSET);
2353 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2354 || retnotsup)
2355 *retcmpp = NFSERR_NOTSAME;
2356 }
2357 attrsum += cnt;
2358 break;
2359 case NFSATTRBIT_FSLAYOUTTYPE:
2360 case NFSATTRBIT_LAYOUTTYPE:
2361 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2362 attrsum += NFSX_UNSIGNED;
2363 i = fxdr_unsigned(int, *tl);
2364 /*
2365 * The RFCs do not define an upper limit for the
2366 * number of layout types, but 32 should be more
2367 * than enough.
2368 */
2369 if (i < 0 || i > 32) {
2370 error = NFSERR_BADXDR;
2371 goto nfsmout;
2372 }
2373 if (i > 0) {
2374 NFSM_DISSECT(tl, u_int32_t *, i *
2375 NFSX_UNSIGNED);
2376 attrsum += i * NFSX_UNSIGNED;
2377 j = fxdr_unsigned(int, *tl);
2378 if (i == 1 && compare && !(*retcmpp) &&
2379 (((nfsrv_doflexfile != 0 ||
2380 nfsrv_maxpnfsmirror > 1) &&
2381 j != NFSLAYOUT_FLEXFILE) ||
2382 (nfsrv_doflexfile == 0 &&
2383 j != NFSLAYOUT_NFSV4_1_FILES)))
2384 *retcmpp = NFSERR_NOTSAME;
2385 }
2386 if (nfsrv_devidcnt == 0) {
2387 if (compare && !(*retcmpp) && i > 0)
2388 *retcmpp = NFSERR_NOTSAME;
2389 } else {
2390 if (compare && !(*retcmpp) && i != 1)
2391 *retcmpp = NFSERR_NOTSAME;
2392 }
2393 break;
2394 case NFSATTRBIT_LAYOUTALIGNMENT:
2395 case NFSATTRBIT_LAYOUTBLKSIZE:
2396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2397 attrsum += NFSX_UNSIGNED;
2398 i = fxdr_unsigned(int, *tl);
2399 if (compare && !(*retcmpp) && i != nfs_srvmaxio)
2400 *retcmpp = NFSERR_NOTSAME;
2401 break;
2402 case NFSATTRBIT_CLONEBLKSIZE:
2403 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2404 if (compare) {
2405 if (!(*retcmpp)) {
2406 if (vp == NULL || VOP_PATHCONF(vp,
2407 _PC_CLONE_BLKSIZE, &has_pathconf)
2408 != 0)
2409 has_pathconf = 0;
2410 if (has_pathconf !=
2411 fxdr_unsigned(uint32_t, *tl))
2412 *retcmpp = NFSERR_NOTSAME;
2413 }
2414 } else if (clone_blksizep != NULL) {
2415 *clone_blksizep = fxdr_unsigned(uint32_t, *tl);
2416 }
2417 attrsum += NFSX_UNSIGNED;
2418 break;
2419 case NFSATTRBIT_CHANGEATTRTYPE:
2420 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2421 if (compare) {
2422 if (!(*retcmpp)) {
2423 tuint = NFSV4CHANGETYPE_UNDEFINED;
2424 if ((vp->v_mount->mnt_vfc->vfc_flags &
2425 VFCF_FILEREVINC) != 0)
2426 tuint = NFSV4CHANGETYPE_VERS_COUNTER_NOPNFS;
2427 else if ((vp->v_mount->mnt_vfc->vfc_flags &
2428 VFCF_FILEREVCT) != 0)
2429 tuint = NFSV4CHANGETYPE_TIME_METADATA;
2430 if (fxdr_unsigned(uint32_t, *tl) != tuint)
2431 *retcmpp = NFSERR_NOTSAME;
2432 }
2433 }
2434 attrsum += NFSX_UNSIGNED;
2435 break;
2436 default:
2437 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2438 bitpos);
2439 if (compare && !(*retcmpp))
2440 *retcmpp = NFSERR_ATTRNOTSUPP;
2441 /*
2442 * and get out of the loop, since we can't parse
2443 * the unknown attribute data.
2444 */
2445 bitpos = NFSATTRBIT_MAX;
2446 break;
2447 }
2448 }
2449
2450 /*
2451 * some clients pad the attrlist, so we need to skip over the
2452 * padding.
2453 */
2454 if (attrsum > attrsize) {
2455 error = NFSERR_BADXDR;
2456 } else {
2457 attrsize = NFSM_RNDUP(attrsize);
2458 if (attrsum < attrsize)
2459 error = nfsm_advance(nd, attrsize - attrsum, -1);
2460 }
2461 nfsmout:
2462 NFSD_CURVNET_RESTORE();
2463 NFSEXITCODE2(error, nd);
2464 return (error);
2465 }
2466
2467 /*
2468 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2469 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2470 * The first argument is a pointer to an nfsv4lock structure.
2471 * The second argument is 1 iff a blocking lock is wanted.
2472 * If this argument is 0, the call waits until no thread either wants nor
2473 * holds an exclusive lock.
2474 * It returns 1 if the lock was acquired, 0 otherwise.
2475 * If several processes call this function concurrently wanting the exclusive
2476 * lock, one will get the lock and the rest will return without getting the
2477 * lock. (If the caller must have the lock, it simply calls this function in a
2478 * loop until the function returns 1 to indicate the lock was acquired.)
2479 * Any usecnt must be decremented by calling nfsv4_relref() before
2480 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2481 * be called in a loop.
2482 * The isleptp argument is set to indicate if the call slept, iff not NULL
2483 * and the mp argument indicates to check for a forced dismount, iff not
2484 * NULL.
2485 */
2486 int
nfsv4_lock(struct nfsv4lock * lp,int iwantlock,int * isleptp,struct mtx * mutex,struct mount * mp)2487 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2488 struct mtx *mutex, struct mount *mp)
2489 {
2490
2491 if (isleptp)
2492 *isleptp = 0;
2493 /*
2494 * If a lock is wanted, loop around until the lock is acquired by
2495 * someone and then released. If I want the lock, try to acquire it.
2496 * For a lock to be issued, no lock must be in force and the usecnt
2497 * must be zero.
2498 */
2499 if (iwantlock) {
2500 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2501 lp->nfslock_usecnt == 0) {
2502 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2503 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2504 return (1);
2505 }
2506 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2507 }
2508 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2509 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2510 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2511 return (0);
2512 }
2513 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2514 if (isleptp)
2515 *isleptp = 1;
2516 msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4lck", hz);
2517 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2518 lp->nfslock_usecnt == 0) {
2519 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2520 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2521 return (1);
2522 }
2523 }
2524 return (0);
2525 }
2526
2527 /*
2528 * Release the lock acquired by nfsv4_lock().
2529 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2530 * incremented, as well.
2531 */
2532 void
nfsv4_unlock(struct nfsv4lock * lp,int incref)2533 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2534 {
2535
2536 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2537 if (incref)
2538 lp->nfslock_usecnt++;
2539 nfsv4_wanted(lp);
2540 }
2541
2542 /*
2543 * Release a reference cnt.
2544 */
2545 void
nfsv4_relref(struct nfsv4lock * lp)2546 nfsv4_relref(struct nfsv4lock *lp)
2547 {
2548
2549 if (lp->nfslock_usecnt <= 0)
2550 panic("nfsv4root ref cnt");
2551 lp->nfslock_usecnt--;
2552 if (lp->nfslock_usecnt == 0)
2553 nfsv4_wanted(lp);
2554 }
2555
2556 /*
2557 * Get a reference cnt.
2558 * This function will wait for any exclusive lock to be released, but will
2559 * not wait for threads that want the exclusive lock. If priority needs
2560 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2561 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2562 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2563 * return without getting a refcnt for that case.
2564 */
2565 void
nfsv4_getref(struct nfsv4lock * lp,int * isleptp,struct mtx * mutex,struct mount * mp)2566 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, struct mtx *mutex,
2567 struct mount *mp)
2568 {
2569
2570 if (isleptp)
2571 *isleptp = 0;
2572
2573 /*
2574 * Wait for a lock held.
2575 */
2576 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2577 if (mp != NULL && NFSCL_FORCEDISM(mp))
2578 return;
2579 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2580 if (isleptp)
2581 *isleptp = 1;
2582 msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4gr", hz);
2583 }
2584 if (mp != NULL && NFSCL_FORCEDISM(mp))
2585 return;
2586
2587 lp->nfslock_usecnt++;
2588 }
2589
2590 /*
2591 * Get a reference as above, but return failure instead of sleeping if
2592 * an exclusive lock is held.
2593 */
2594 int
nfsv4_getref_nonblock(struct nfsv4lock * lp)2595 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2596 {
2597
2598 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2599 return (0);
2600
2601 lp->nfslock_usecnt++;
2602 return (1);
2603 }
2604
2605 /*
2606 * Test for a lock. Return 1 if locked, 0 otherwise.
2607 */
2608 int
nfsv4_testlock(struct nfsv4lock * lp)2609 nfsv4_testlock(struct nfsv4lock *lp)
2610 {
2611
2612 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2613 lp->nfslock_usecnt == 0)
2614 return (0);
2615 return (1);
2616 }
2617
2618 /*
2619 * Wake up anyone sleeping, waiting for this lock.
2620 */
2621 static void
nfsv4_wanted(struct nfsv4lock * lp)2622 nfsv4_wanted(struct nfsv4lock *lp)
2623 {
2624
2625 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2626 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2627 wakeup((caddr_t)&lp->nfslock_lock);
2628 }
2629 }
2630
2631 /*
2632 * Copy a string from an mbuf list into a character array.
2633 * Return EBADRPC if there is an mbuf error,
2634 * 0 otherwise.
2635 */
2636 int
nfsrv_mtostr(struct nfsrv_descript * nd,char * str,int siz)2637 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2638 {
2639 char *cp;
2640 int xfer, len;
2641 struct mbuf *mp;
2642 int rem, error = 0;
2643
2644 mp = nd->nd_md;
2645 cp = nd->nd_dpos;
2646 len = mtod(mp, caddr_t) + mp->m_len - cp;
2647 rem = NFSM_RNDUP(siz) - siz;
2648 while (siz > 0) {
2649 if (len > siz)
2650 xfer = siz;
2651 else
2652 xfer = len;
2653 NFSBCOPY(cp, str, xfer);
2654 str += xfer;
2655 siz -= xfer;
2656 if (siz > 0) {
2657 mp = mp->m_next;
2658 if (mp == NULL) {
2659 error = EBADRPC;
2660 goto out;
2661 }
2662 cp = mtod(mp, caddr_t);
2663 len = mp->m_len;
2664 } else {
2665 cp += xfer;
2666 len -= xfer;
2667 }
2668 }
2669 *str = '\0';
2670 nd->nd_dpos = cp;
2671 nd->nd_md = mp;
2672 if (rem > 0) {
2673 if (len < rem)
2674 error = nfsm_advance(nd, rem, len);
2675 else
2676 nd->nd_dpos += rem;
2677 }
2678
2679 out:
2680 NFSEXITCODE2(error, nd);
2681 return (error);
2682 }
2683
2684 /*
2685 * Fill in the attributes as marked by the bitmap (V4).
2686 */
2687 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)2688 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2689 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2690 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2691 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2692 struct statfs *pnfssf, bool xattrsupp, bool has_hiddensystem,
2693 bool has_namedattr, uint32_t clone_blksize)
2694 {
2695 int bitpos, retnum = 0;
2696 u_int32_t *tl;
2697 int siz, prefixnum, error;
2698 u_char *cp, namestr[NFSV4_SMALLSTR];
2699 nfsattrbit_t attrbits, retbits;
2700 nfsattrbit_t *retbitp = &retbits;
2701 u_int32_t freenum, *retnump;
2702 u_int64_t uquad;
2703 struct statfs *fs;
2704 struct nfsfsinfo fsinf;
2705 struct timespec temptime;
2706 NFSACL_T *aclp, *naclp = NULL;
2707 short irflag;
2708 #ifdef QUOTA
2709 struct dqblk dqb;
2710 uid_t savuid;
2711 #endif
2712
2713 /*
2714 * First, set the bits that can be filled and get fsinfo.
2715 */
2716 NFSSET_ATTRBIT(retbitp, attrbitp);
2717 /*
2718 * If both p and cred are NULL, it is a client side setattr call.
2719 * If both p and cred are not NULL, it is a server side reply call.
2720 * If p is not NULL and cred is NULL, it is a client side callback
2721 * reply call.
2722 */
2723 if (p == NULL && cred == NULL) {
2724 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2725 aclp = saclp;
2726 } else {
2727 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2728 naclp = acl_alloc(M_WAITOK);
2729 aclp = naclp;
2730 }
2731 nfsvno_getfs(&fsinf, isdgram);
2732 /*
2733 * Get the VFS_STATFS(), since some attributes need them.
2734 */
2735 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2736 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2737 error = VFS_STATFS(mp, fs);
2738 if (error != 0) {
2739 if (reterr) {
2740 nd->nd_repstat = NFSERR_ACCES;
2741 free(fs, M_STATFS);
2742 return (0);
2743 }
2744 NFSCLRSTATFS_ATTRBIT(retbitp);
2745 }
2746 /*
2747 * Since NFS handles these values as unsigned on the
2748 * wire, there is no way to represent negative values,
2749 * so set them to 0. Without this, they will appear
2750 * to be very large positive values for clients like
2751 * Solaris10.
2752 */
2753 if (fs->f_bavail < 0)
2754 fs->f_bavail = 0;
2755 if (fs->f_ffree < 0)
2756 fs->f_ffree = 0;
2757 }
2758
2759 /*
2760 * And the NFSv4 ACL...
2761 */
2762 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2763 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2764 supports_nfsv4acls == 0))) {
2765 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2766 }
2767 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2768 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2769 supports_nfsv4acls == 0)) {
2770 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2771 } else if (naclp != NULL) {
2772 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2773 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2774 if (error == 0)
2775 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2776 naclp, cred, p);
2777 NFSVOPUNLOCK(vp);
2778 } else
2779 error = NFSERR_PERM;
2780 if (error != 0) {
2781 if (reterr) {
2782 nd->nd_repstat = NFSERR_ACCES;
2783 free(fs, M_STATFS);
2784 return (0);
2785 }
2786 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2787 }
2788 }
2789 }
2790
2791 /*
2792 * Put out the attribute bitmap for the ones being filled in
2793 * and get the field for the number of attributes returned.
2794 */
2795 prefixnum = nfsrv_putattrbit(nd, retbitp);
2796 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2797 prefixnum += NFSX_UNSIGNED;
2798
2799 /*
2800 * Now, loop around filling in the attributes for each bit set.
2801 */
2802 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2803 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2804 switch (bitpos) {
2805 case NFSATTRBIT_SUPPORTEDATTRS:
2806 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2807 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2808 && supports_nfsv4acls == 0)) {
2809 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2810 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2811 }
2812 if (!has_hiddensystem) {
2813 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
2814 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
2815 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_ARCHIVE);
2816 }
2817 if (clone_blksize == 0)
2818 NFSCLRBIT_ATTRBIT(&attrbits,
2819 NFSATTRBIT_CLONEBLKSIZE);
2820 retnum += nfsrv_putattrbit(nd, &attrbits);
2821 break;
2822 case NFSATTRBIT_TYPE:
2823 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2824 *tl = vtonfsv4_type(vap);
2825 retnum += NFSX_UNSIGNED;
2826 break;
2827 case NFSATTRBIT_FHEXPIRETYPE:
2828 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2829 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2830 retnum += NFSX_UNSIGNED;
2831 break;
2832 case NFSATTRBIT_CHANGE:
2833 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2834 txdr_hyper(vap->va_filerev, tl);
2835 retnum += NFSX_HYPER;
2836 break;
2837 case NFSATTRBIT_SIZE:
2838 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2839 txdr_hyper(vap->va_size, tl);
2840 retnum += NFSX_HYPER;
2841 break;
2842 case NFSATTRBIT_LINKSUPPORT:
2843 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2844 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2845 *tl = newnfs_true;
2846 else
2847 *tl = newnfs_false;
2848 retnum += NFSX_UNSIGNED;
2849 break;
2850 case NFSATTRBIT_SYMLINKSUPPORT:
2851 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2852 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2853 *tl = newnfs_true;
2854 else
2855 *tl = newnfs_false;
2856 retnum += NFSX_UNSIGNED;
2857 break;
2858 case NFSATTRBIT_NAMEDATTR:
2859 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2860 if (has_namedattr)
2861 *tl = newnfs_true;
2862 else
2863 *tl = newnfs_false;
2864 retnum += NFSX_UNSIGNED;
2865 break;
2866 case NFSATTRBIT_FSID:
2867 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2868 *tl++ = 0;
2869 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2870 *tl++ = 0;
2871 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2872 retnum += NFSX_V4FSID;
2873 break;
2874 case NFSATTRBIT_UNIQUEHANDLES:
2875 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2876 *tl = newnfs_true;
2877 retnum += NFSX_UNSIGNED;
2878 break;
2879 case NFSATTRBIT_LEASETIME:
2880 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2881 *tl = txdr_unsigned(nfsrv_lease);
2882 retnum += NFSX_UNSIGNED;
2883 break;
2884 case NFSATTRBIT_RDATTRERROR:
2885 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2886 *tl = txdr_unsigned(rderror);
2887 retnum += NFSX_UNSIGNED;
2888 break;
2889 /*
2890 * Recommended Attributes. (Only the supported ones.)
2891 */
2892 case NFSATTRBIT_ACL:
2893 retnum += nfsrv_buildacl(nd, aclp, vp->v_type, p);
2894 break;
2895 case NFSATTRBIT_ACLSUPPORT:
2896 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2897 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2898 retnum += NFSX_UNSIGNED;
2899 break;
2900 case NFSATTRBIT_ARCHIVE:
2901 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
2902 if ((vap->va_flags & UF_ARCHIVE) != 0)
2903 *tl = newnfs_true;
2904 else
2905 *tl = newnfs_false;
2906 retnum += NFSX_UNSIGNED;
2907 break;
2908 case NFSATTRBIT_CANSETTIME:
2909 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2910 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2911 *tl = newnfs_true;
2912 else
2913 *tl = newnfs_false;
2914 retnum += NFSX_UNSIGNED;
2915 break;
2916 case NFSATTRBIT_CASEINSENSITIVE:
2917 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2918 *tl = newnfs_false;
2919 retnum += NFSX_UNSIGNED;
2920 break;
2921 case NFSATTRBIT_CASEPRESERVING:
2922 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2923 *tl = newnfs_true;
2924 retnum += NFSX_UNSIGNED;
2925 break;
2926 case NFSATTRBIT_CHOWNRESTRICTED:
2927 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2928 *tl = newnfs_true;
2929 retnum += NFSX_UNSIGNED;
2930 break;
2931 case NFSATTRBIT_FILEHANDLE:
2932 siz = 0;
2933 if (vp != NULL) {
2934 irflag = vn_irflag_read(vp);
2935 if ((irflag & VIRF_NAMEDDIR) != 0)
2936 siz = NFSX_FHMAX + 2;
2937 else if ((irflag & VIRF_NAMEDATTR) != 0)
2938 siz = NFSX_FHMAX + 3;
2939 }
2940 retnum += nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, siz, 0);
2941 break;
2942 case NFSATTRBIT_FILEID:
2943 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2944 uquad = vap->va_fileid;
2945 txdr_hyper(uquad, tl);
2946 retnum += NFSX_HYPER;
2947 break;
2948 case NFSATTRBIT_FILESAVAIL:
2949 freenum = nfsv4_filesavail(fs, mp);
2950 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2951 *tl++ = 0;
2952 *tl = txdr_unsigned(freenum);
2953 retnum += NFSX_HYPER;
2954 break;
2955 case NFSATTRBIT_FILESFREE:
2956 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2957 *tl++ = 0;
2958 *tl = txdr_unsigned(fs->f_ffree);
2959 retnum += NFSX_HYPER;
2960 break;
2961 case NFSATTRBIT_FILESTOTAL:
2962 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2963 *tl++ = 0;
2964 *tl = txdr_unsigned(fs->f_files);
2965 retnum += NFSX_HYPER;
2966 break;
2967 case NFSATTRBIT_FSLOCATIONS:
2968 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2969 *tl++ = 0;
2970 *tl = 0;
2971 retnum += 2 * NFSX_UNSIGNED;
2972 break;
2973 case NFSATTRBIT_HIDDEN:
2974 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
2975 if ((vap->va_flags & UF_HIDDEN) != 0)
2976 *tl = newnfs_true;
2977 else
2978 *tl = newnfs_false;
2979 retnum += NFSX_UNSIGNED;
2980 break;
2981 case NFSATTRBIT_HOMOGENEOUS:
2982 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2983 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2984 *tl = newnfs_true;
2985 else
2986 *tl = newnfs_false;
2987 retnum += NFSX_UNSIGNED;
2988 break;
2989 case NFSATTRBIT_MAXFILESIZE:
2990 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2991 uquad = NFSRV_MAXFILESIZE;
2992 txdr_hyper(uquad, tl);
2993 retnum += NFSX_HYPER;
2994 break;
2995 case NFSATTRBIT_MAXLINK:
2996 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2997 *tl = txdr_unsigned(NFS_LINK_MAX);
2998 retnum += NFSX_UNSIGNED;
2999 break;
3000 case NFSATTRBIT_MAXNAME:
3001 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3002 *tl = txdr_unsigned(NFS_MAXNAMLEN);
3003 retnum += NFSX_UNSIGNED;
3004 break;
3005 case NFSATTRBIT_MAXREAD:
3006 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3007 *tl++ = 0;
3008 *tl = txdr_unsigned(fsinf.fs_rtmax);
3009 retnum += NFSX_HYPER;
3010 break;
3011 case NFSATTRBIT_MAXWRITE:
3012 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3013 *tl++ = 0;
3014 *tl = txdr_unsigned(fsinf.fs_wtmax);
3015 retnum += NFSX_HYPER;
3016 break;
3017 case NFSATTRBIT_MODE:
3018 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3019 *tl = vtonfsv34_mode(vap->va_mode);
3020 retnum += NFSX_UNSIGNED;
3021 break;
3022 case NFSATTRBIT_NOTRUNC:
3023 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3024 *tl = newnfs_true;
3025 retnum += NFSX_UNSIGNED;
3026 break;
3027 case NFSATTRBIT_NUMLINKS:
3028 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3029 *tl = txdr_unsigned(vap->va_nlink);
3030 retnum += NFSX_UNSIGNED;
3031 break;
3032 case NFSATTRBIT_OWNER:
3033 cp = namestr;
3034 nfsv4_uidtostr(vap->va_uid, &cp, &siz);
3035 retnum += nfsm_strtom(nd, cp, siz);
3036 if (cp != namestr)
3037 free(cp, M_NFSSTRING);
3038 break;
3039 case NFSATTRBIT_OWNERGROUP:
3040 cp = namestr;
3041 nfsv4_gidtostr(vap->va_gid, &cp, &siz);
3042 retnum += nfsm_strtom(nd, cp, siz);
3043 if (cp != namestr)
3044 free(cp, M_NFSSTRING);
3045 break;
3046 case NFSATTRBIT_QUOTAHARD:
3047 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
3048 freenum = fs->f_bfree;
3049 else
3050 freenum = fs->f_bavail;
3051 #ifdef QUOTA
3052 /*
3053 * ufs_quotactl() insists that the uid argument
3054 * equal p_ruid for non-root quota access, so
3055 * we'll just make sure that's the case.
3056 */
3057 savuid = p->p_cred->p_ruid;
3058 p->p_cred->p_ruid = cred->cr_uid;
3059 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3060 cred->cr_uid, &dqb))
3061 freenum = min(dqb.dqb_bhardlimit, freenum);
3062 p->p_cred->p_ruid = savuid;
3063 #endif /* QUOTA */
3064 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3065 uquad = (u_int64_t)freenum;
3066 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
3067 txdr_hyper(uquad, tl);
3068 retnum += NFSX_HYPER;
3069 break;
3070 case NFSATTRBIT_QUOTASOFT:
3071 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
3072 freenum = fs->f_bfree;
3073 else
3074 freenum = fs->f_bavail;
3075 #ifdef QUOTA
3076 /*
3077 * ufs_quotactl() insists that the uid argument
3078 * equal p_ruid for non-root quota access, so
3079 * we'll just make sure that's the case.
3080 */
3081 savuid = p->p_cred->p_ruid;
3082 p->p_cred->p_ruid = cred->cr_uid;
3083 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3084 cred->cr_uid, &dqb))
3085 freenum = min(dqb.dqb_bsoftlimit, freenum);
3086 p->p_cred->p_ruid = savuid;
3087 #endif /* QUOTA */
3088 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3089 uquad = (u_int64_t)freenum;
3090 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
3091 txdr_hyper(uquad, tl);
3092 retnum += NFSX_HYPER;
3093 break;
3094 case NFSATTRBIT_QUOTAUSED:
3095 freenum = 0;
3096 #ifdef QUOTA
3097 /*
3098 * ufs_quotactl() insists that the uid argument
3099 * equal p_ruid for non-root quota access, so
3100 * we'll just make sure that's the case.
3101 */
3102 savuid = p->p_cred->p_ruid;
3103 p->p_cred->p_ruid = cred->cr_uid;
3104 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3105 cred->cr_uid, &dqb))
3106 freenum = dqb.dqb_curblocks;
3107 p->p_cred->p_ruid = savuid;
3108 #endif /* QUOTA */
3109 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3110 uquad = (u_int64_t)freenum;
3111 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
3112 txdr_hyper(uquad, tl);
3113 retnum += NFSX_HYPER;
3114 break;
3115 case NFSATTRBIT_RAWDEV:
3116 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
3117 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
3118 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
3119 retnum += NFSX_V4SPECDATA;
3120 break;
3121 case NFSATTRBIT_SPACEAVAIL:
3122 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3123 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
3124 if (pnfssf != NULL)
3125 uquad = (u_int64_t)pnfssf->f_bfree;
3126 else
3127 uquad = (u_int64_t)fs->f_bfree;
3128 } else {
3129 if (pnfssf != NULL)
3130 uquad = (u_int64_t)pnfssf->f_bavail;
3131 else
3132 uquad = (u_int64_t)fs->f_bavail;
3133 }
3134 if (pnfssf != NULL)
3135 uquad *= pnfssf->f_bsize;
3136 else
3137 uquad *= fs->f_bsize;
3138 txdr_hyper(uquad, tl);
3139 retnum += NFSX_HYPER;
3140 break;
3141 case NFSATTRBIT_SPACEFREE:
3142 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3143 if (pnfssf != NULL) {
3144 uquad = (u_int64_t)pnfssf->f_bfree;
3145 uquad *= pnfssf->f_bsize;
3146 } else {
3147 uquad = (u_int64_t)fs->f_bfree;
3148 uquad *= fs->f_bsize;
3149 }
3150 txdr_hyper(uquad, tl);
3151 retnum += NFSX_HYPER;
3152 break;
3153 case NFSATTRBIT_SPACETOTAL:
3154 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3155 if (pnfssf != NULL) {
3156 uquad = (u_int64_t)pnfssf->f_blocks;
3157 uquad *= pnfssf->f_bsize;
3158 } else {
3159 uquad = (u_int64_t)fs->f_blocks;
3160 uquad *= fs->f_bsize;
3161 }
3162 txdr_hyper(uquad, tl);
3163 retnum += NFSX_HYPER;
3164 break;
3165 case NFSATTRBIT_SPACEUSED:
3166 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3167 txdr_hyper(vap->va_bytes, tl);
3168 retnum += NFSX_HYPER;
3169 break;
3170 case NFSATTRBIT_SYSTEM:
3171 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3172 if ((vap->va_flags & UF_SYSTEM) != 0)
3173 *tl = newnfs_true;
3174 else
3175 *tl = newnfs_false;
3176 retnum += NFSX_UNSIGNED;
3177 break;
3178 case NFSATTRBIT_TIMEACCESS:
3179 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3180 txdr_nfsv4time(&vap->va_atime, tl);
3181 retnum += NFSX_V4TIME;
3182 break;
3183 case NFSATTRBIT_TIMEACCESSSET:
3184 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
3185 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
3186 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
3187 txdr_nfsv4time(&vap->va_atime, tl);
3188 retnum += NFSX_V4SETTIME;
3189 } else {
3190 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3191 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
3192 retnum += NFSX_UNSIGNED;
3193 }
3194 break;
3195 case NFSATTRBIT_TIMEDELTA:
3196 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3197 temptime.tv_sec = 0;
3198 temptime.tv_nsec = 1000000000 / hz;
3199 txdr_nfsv4time(&temptime, tl);
3200 retnum += NFSX_V4TIME;
3201 break;
3202 case NFSATTRBIT_TIMEMETADATA:
3203 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3204 txdr_nfsv4time(&vap->va_ctime, tl);
3205 retnum += NFSX_V4TIME;
3206 break;
3207 case NFSATTRBIT_TIMEMODIFY:
3208 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3209 txdr_nfsv4time(&vap->va_mtime, tl);
3210 retnum += NFSX_V4TIME;
3211 break;
3212 case NFSATTRBIT_TIMECREATE:
3213 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3214 txdr_nfsv4time(&vap->va_birthtime, tl);
3215 retnum += NFSX_V4TIME;
3216 break;
3217 case NFSATTRBIT_TIMEMODIFYSET:
3218 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
3219 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
3220 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
3221 txdr_nfsv4time(&vap->va_mtime, tl);
3222 retnum += NFSX_V4SETTIME;
3223 } else {
3224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3225 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
3226 retnum += NFSX_UNSIGNED;
3227 }
3228 break;
3229 case NFSATTRBIT_MOUNTEDONFILEID:
3230 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3231 if (at_root != 0)
3232 uquad = mounted_on_fileno;
3233 else
3234 uquad = vap->va_fileid;
3235 txdr_hyper(uquad, tl);
3236 retnum += NFSX_HYPER;
3237 break;
3238 case NFSATTRBIT_SUPPATTREXCLCREAT:
3239 NFSSETSUPP_ATTRBIT(&attrbits, nd);
3240 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
3241 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
3242 retnum += nfsrv_putattrbit(nd, &attrbits);
3243 break;
3244 case NFSATTRBIT_FSLAYOUTTYPE:
3245 case NFSATTRBIT_LAYOUTTYPE:
3246 if (nfsrv_devidcnt == 0)
3247 siz = 1;
3248 else
3249 siz = 2;
3250 if (siz == 2) {
3251 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3252 *tl++ = txdr_unsigned(1); /* One entry. */
3253 if (nfsrv_doflexfile != 0 ||
3254 nfsrv_maxpnfsmirror > 1)
3255 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3256 else
3257 *tl = txdr_unsigned(
3258 NFSLAYOUT_NFSV4_1_FILES);
3259 } else {
3260 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3261 *tl = 0;
3262 }
3263 retnum += siz * NFSX_UNSIGNED;
3264 break;
3265 case NFSATTRBIT_LAYOUTALIGNMENT:
3266 case NFSATTRBIT_LAYOUTBLKSIZE:
3267 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3268 *tl = txdr_unsigned(nfs_srvmaxio);
3269 retnum += NFSX_UNSIGNED;
3270 break;
3271 case NFSATTRBIT_XATTRSUPPORT:
3272 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3273 if (xattrsupp)
3274 *tl = newnfs_true;
3275 else
3276 *tl = newnfs_false;
3277 retnum += NFSX_UNSIGNED;
3278 break;
3279 case NFSATTRBIT_MODEUMASK:
3280 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3281 /*
3282 * Since FreeBSD applies the umask above the VFS/VOP,
3283 * there is no umask to handle here. If FreeBSD
3284 * moves handling of umask to below the VFS/VOP,
3285 * this could change.
3286 */
3287 *tl++ = vtonfsv34_mode(vap->va_mode);
3288 *tl = 0;
3289 retnum += 2 * NFSX_UNSIGNED;
3290 break;
3291 case NFSATTRBIT_CHANGEATTRTYPE:
3292 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3293 *tl = txdr_unsigned(NFSV4CHANGETYPE_UNDEFINED);
3294 if (mp != NULL) {
3295 if ((mp->mnt_vfc->vfc_flags &
3296 VFCF_FILEREVINC) != 0)
3297 *tl = txdr_unsigned(
3298 NFSV4CHANGETYPE_VERS_COUNTER_NOPNFS);
3299 else if ((mp->mnt_vfc->vfc_flags &
3300 VFCF_FILEREVCT) != 0)
3301 *tl = txdr_unsigned(
3302 NFSV4CHANGETYPE_TIME_METADATA);
3303 }
3304 retnum += NFSX_UNSIGNED;
3305 break;
3306 case NFSATTRBIT_CLONEBLKSIZE:
3307 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3308 *tl = txdr_unsigned(clone_blksize);
3309 retnum += NFSX_UNSIGNED;
3310 break;
3311 default:
3312 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3313 }
3314 }
3315 }
3316 if (naclp != NULL)
3317 acl_free(naclp);
3318 free(fs, M_STATFS);
3319 *retnump = txdr_unsigned(retnum);
3320 return (retnum + prefixnum);
3321 }
3322
3323 /*
3324 * Calculate the files available attribute value.
3325 */
3326 static uint32_t
nfsv4_filesavail(struct statfs * fs,struct mount * mp)3327 nfsv4_filesavail(struct statfs *fs, struct mount *mp)
3328 {
3329 uint32_t freenum;
3330 #ifdef QUOTA
3331 struct dqblk dqb;
3332 uid_t savuid;
3333 NFSPROC_T *p;
3334 #endif
3335
3336 /*
3337 * Check quota and use min(quota, f_ffree).
3338 */
3339 freenum = fs->f_ffree;
3340 #ifdef QUOTA
3341 /*
3342 * This is old OpenBSD code that does not build
3343 * for FreeBSD. I do not know if doing this is
3344 * useful, so I will just leave the code here.
3345 */
3346 p = curthread();
3347 /*
3348 * ufs_quotactl() insists that the uid argument
3349 * equal p_ruid for non-root quota access, so
3350 * we'll just make sure that's the case.
3351 */
3352 savuid = p->p_cred->p_ruid;
3353 p->p_cred->p_ruid = cred->cr_uid;
3354 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3355 cred->cr_uid, &dqb))
3356 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
3357 freenum);
3358 p->p_cred->p_ruid = savuid;
3359 #endif /* QUOTA */
3360 return (freenum);
3361 }
3362
3363 /*
3364 * Put the attribute bits onto an mbuf list.
3365 * Return the number of bytes of output generated.
3366 */
3367 int
nfsrv_putattrbit(struct nfsrv_descript * nd,nfsattrbit_t * attrbitp)3368 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3369 {
3370 u_int32_t *tl;
3371 int cnt, i, bytesize;
3372
3373 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3374 if (attrbitp->bits[cnt - 1])
3375 break;
3376 bytesize = (cnt + 1) * NFSX_UNSIGNED;
3377 NFSM_BUILD(tl, u_int32_t *, bytesize);
3378 *tl++ = txdr_unsigned(cnt);
3379 for (i = 0; i < cnt; i++)
3380 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3381 return (bytesize);
3382 }
3383
3384 /*
3385 * Put the operation bits onto an mbuf list.
3386 * Return the number of bytes of output generated.
3387 */
3388 int
nfsrv_putopbit(struct nfsrv_descript * nd,nfsopbit_t * opbitp)3389 nfsrv_putopbit(struct nfsrv_descript *nd, nfsopbit_t *opbitp)
3390 {
3391 uint32_t *tl;
3392 int cnt, i, bytesize;
3393
3394 for (cnt = NFSOPBIT_MAXWORDS; cnt > 0; cnt--)
3395 if (opbitp->bits[cnt - 1])
3396 break;
3397 bytesize = (cnt + 1) * NFSX_UNSIGNED;
3398 NFSM_BUILD(tl, uint32_t *, bytesize);
3399 *tl++ = txdr_unsigned(cnt);
3400 for (i = 0; i < cnt; i++)
3401 *tl++ = txdr_unsigned(opbitp->bits[i]);
3402 return (bytesize);
3403 }
3404
3405 /*
3406 * Convert a uid to a string.
3407 * If the lookup fails, just output the digits.
3408 * uid - the user id
3409 * cpp - points to a buffer of size NFSV4_SMALLSTR
3410 * (malloc a larger one, as required)
3411 * retlenp - pointer to length to be returned
3412 */
3413 void
nfsv4_uidtostr(uid_t uid,u_char ** cpp,int * retlenp)3414 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3415 {
3416 int i;
3417 struct nfsusrgrp *usrp;
3418 u_char *cp = *cpp;
3419 uid_t tmp;
3420 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3421 struct nfsrv_lughash *hp;
3422
3423 NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3424 cnt = 0;
3425 tryagain:
3426 if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
3427 !NFSD_VNET(nfs_enable_uidtostring)) {
3428 /*
3429 * Always map nfsrv_defaultuid to "nobody".
3430 */
3431 if (uid == NFSD_VNET(nfsrv_defaultuid)) {
3432 i = NFSD_VNET(nfsrv_dnsnamelen) + 7;
3433 if (i > len) {
3434 if (len > NFSV4_SMALLSTR)
3435 free(cp, M_NFSSTRING);
3436 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3437 *cpp = cp;
3438 len = i;
3439 goto tryagain;
3440 }
3441 *retlenp = i;
3442 NFSBCOPY("nobody@", cp, 7);
3443 cp += 7;
3444 NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3445 NFSD_VNET(nfsrv_dnsnamelen));
3446 NFSD_CURVNET_RESTORE();
3447 return;
3448 }
3449 hasampersand = 0;
3450 hp = NFSUSERHASH(uid);
3451 mtx_lock(&hp->mtx);
3452 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3453 if (usrp->lug_uid == uid) {
3454 if (usrp->lug_expiry < NFSD_MONOSEC)
3455 break;
3456 /*
3457 * If the name doesn't already have an '@'
3458 * in it, append @domainname to it.
3459 */
3460 for (i = 0; i < usrp->lug_namelen; i++) {
3461 if (usrp->lug_name[i] == '@') {
3462 hasampersand = 1;
3463 break;
3464 }
3465 }
3466 if (hasampersand)
3467 i = usrp->lug_namelen;
3468 else
3469 i = usrp->lug_namelen +
3470 NFSD_VNET(nfsrv_dnsnamelen) + 1;
3471 if (i > len) {
3472 mtx_unlock(&hp->mtx);
3473 if (len > NFSV4_SMALLSTR)
3474 free(cp, M_NFSSTRING);
3475 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3476 *cpp = cp;
3477 len = i;
3478 goto tryagain;
3479 }
3480 *retlenp = i;
3481 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3482 if (!hasampersand) {
3483 cp += usrp->lug_namelen;
3484 *cp++ = '@';
3485 NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3486 NFSD_VNET(nfsrv_dnsnamelen));
3487 }
3488 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3489 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3490 lug_numhash);
3491 mtx_unlock(&hp->mtx);
3492 NFSD_CURVNET_RESTORE();
3493 return;
3494 }
3495 }
3496 mtx_unlock(&hp->mtx);
3497 cnt++;
3498 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3499 if (ret == 0 && cnt < 2)
3500 goto tryagain;
3501 }
3502
3503 /*
3504 * No match, just return a string of digits.
3505 */
3506 tmp = uid;
3507 i = 0;
3508 while (tmp || i == 0) {
3509 tmp /= 10;
3510 i++;
3511 }
3512 len = (i > len) ? len : i;
3513 *retlenp = len;
3514 cp += (len - 1);
3515 tmp = uid;
3516 for (i = 0; i < len; i++) {
3517 *cp-- = '0' + (tmp % 10);
3518 tmp /= 10;
3519 }
3520 NFSD_CURVNET_RESTORE();
3521 return;
3522 }
3523
3524 /*
3525 * Get a credential for the uid with the server's group list.
3526 * If none is found, just return the credential passed in after
3527 * logging a warning message.
3528 */
3529 struct ucred *
nfsrv_getgrpscred(struct ucred * oldcred)3530 nfsrv_getgrpscred(struct ucred *oldcred)
3531 {
3532 struct nfsusrgrp *usrp;
3533 struct ucred *newcred;
3534 int cnt, ret;
3535 uid_t uid;
3536 struct nfsrv_lughash *hp;
3537
3538 cnt = 0;
3539 uid = oldcred->cr_uid;
3540 tryagain:
3541 if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
3542 hp = NFSUSERHASH(uid);
3543 mtx_lock(&hp->mtx);
3544 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3545 if (usrp->lug_uid == uid) {
3546 if (usrp->lug_expiry < NFSD_MONOSEC)
3547 break;
3548 if (usrp->lug_cred != NULL) {
3549 newcred = crhold(usrp->lug_cred);
3550 crfree(oldcred);
3551 } else
3552 newcred = oldcred;
3553 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3554 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3555 lug_numhash);
3556 mtx_unlock(&hp->mtx);
3557 return (newcred);
3558 }
3559 }
3560 mtx_unlock(&hp->mtx);
3561 cnt++;
3562 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3563 if (ret == 0 && cnt < 2)
3564 goto tryagain;
3565 }
3566 return (oldcred);
3567 }
3568
3569 /*
3570 * Convert a string to a uid.
3571 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3572 * return 0.
3573 * If this is called from a client side mount using AUTH_SYS and the
3574 * string is made up entirely of digits, just convert the string to
3575 * a number.
3576 */
3577 int
nfsv4_strtouid(struct nfsrv_descript * nd,u_char * str,int len,uid_t * uidp)3578 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3579 {
3580 int i;
3581 char *cp, *endstr, *str0;
3582 struct nfsusrgrp *usrp;
3583 int cnt, ret;
3584 int error = 0;
3585 uid_t tuid;
3586 struct nfsrv_lughash *hp, *hp2;
3587
3588 NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3589 if (len == 0) {
3590 error = NFSERR_BADOWNER;
3591 goto out;
3592 }
3593 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3594 str0 = str;
3595 tuid = (uid_t)strtoul(str0, &endstr, 10);
3596 if ((endstr - str0) == len) {
3597 /* A numeric string. */
3598 if ((nd->nd_flag & ND_KERBV) == 0 &&
3599 ((nd->nd_flag & ND_NFSCL) != 0 ||
3600 NFSD_VNET(nfsd_enable_stringtouid) != 0))
3601 *uidp = tuid;
3602 else
3603 error = NFSERR_BADOWNER;
3604 goto out;
3605 }
3606 /*
3607 * Look for an '@'.
3608 */
3609 cp = strchr(str0, '@');
3610 if (cp != NULL)
3611 i = (int)(cp++ - str0);
3612 else
3613 i = len;
3614
3615 cnt = 0;
3616 tryagain:
3617 if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
3618 /*
3619 * If an '@' is found and the domain name matches, search for
3620 * the name with dns stripped off.
3621 * The match for alphabetics in now case insensitive,
3622 * since RFC8881 defines this string as a DNS domain name.
3623 */
3624 if (cnt == 0 && i < len && i > 0 &&
3625 (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
3626 strncasecmp(cp, NFSD_VNET(nfsrv_dnsname),
3627 NFSD_VNET(nfsrv_dnsnamelen)) == 0) {
3628 len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
3629 *(cp - 1) = '\0';
3630 }
3631
3632 /*
3633 * Check for the special case of "nobody".
3634 */
3635 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3636 *uidp = NFSD_VNET(nfsrv_defaultuid);
3637 error = 0;
3638 goto out;
3639 }
3640
3641 hp = NFSUSERNAMEHASH(str, len);
3642 mtx_lock(&hp->mtx);
3643 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3644 if (usrp->lug_namelen == len &&
3645 !NFSBCMP(usrp->lug_name, str, len)) {
3646 if (usrp->lug_expiry < NFSD_MONOSEC)
3647 break;
3648 hp2 = NFSUSERHASH(usrp->lug_uid);
3649 mtx_lock(&hp2->mtx);
3650 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3651 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3652 lug_numhash);
3653 *uidp = usrp->lug_uid;
3654 mtx_unlock(&hp2->mtx);
3655 mtx_unlock(&hp->mtx);
3656 error = 0;
3657 goto out;
3658 }
3659 }
3660 mtx_unlock(&hp->mtx);
3661 cnt++;
3662 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3663 str);
3664 if (ret == 0 && cnt < 2)
3665 goto tryagain;
3666 }
3667 error = NFSERR_BADOWNER;
3668
3669 out:
3670 NFSD_CURVNET_RESTORE();
3671 NFSEXITCODE(error);
3672 return (error);
3673 }
3674
3675 /*
3676 * Convert a gid to a string.
3677 * gid - the group id
3678 * cpp - points to a buffer of size NFSV4_SMALLSTR
3679 * (malloc a larger one, as required)
3680 * retlenp - pointer to length to be returned
3681 */
3682 void
nfsv4_gidtostr(gid_t gid,u_char ** cpp,int * retlenp)3683 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3684 {
3685 int i;
3686 struct nfsusrgrp *usrp;
3687 u_char *cp = *cpp;
3688 gid_t tmp;
3689 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3690 struct nfsrv_lughash *hp;
3691
3692 NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3693 cnt = 0;
3694 tryagain:
3695 if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
3696 !NFSD_VNET(nfs_enable_uidtostring)) {
3697 /*
3698 * Always map nfsrv_defaultgid to "nogroup".
3699 */
3700 if (gid == NFSD_VNET(nfsrv_defaultgid)) {
3701 i = NFSD_VNET(nfsrv_dnsnamelen) + 8;
3702 if (i > len) {
3703 if (len > NFSV4_SMALLSTR)
3704 free(cp, M_NFSSTRING);
3705 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3706 *cpp = cp;
3707 len = i;
3708 goto tryagain;
3709 }
3710 *retlenp = i;
3711 NFSBCOPY("nogroup@", cp, 8);
3712 cp += 8;
3713 NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3714 NFSD_VNET(nfsrv_dnsnamelen));
3715 NFSD_CURVNET_RESTORE();
3716 return;
3717 }
3718 hasampersand = 0;
3719 hp = NFSGROUPHASH(gid);
3720 mtx_lock(&hp->mtx);
3721 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3722 if (usrp->lug_gid == gid) {
3723 if (usrp->lug_expiry < NFSD_MONOSEC)
3724 break;
3725 /*
3726 * If the name doesn't already have an '@'
3727 * in it, append @domainname to it.
3728 */
3729 for (i = 0; i < usrp->lug_namelen; i++) {
3730 if (usrp->lug_name[i] == '@') {
3731 hasampersand = 1;
3732 break;
3733 }
3734 }
3735 if (hasampersand)
3736 i = usrp->lug_namelen;
3737 else
3738 i = usrp->lug_namelen +
3739 NFSD_VNET(nfsrv_dnsnamelen) + 1;
3740 if (i > len) {
3741 mtx_unlock(&hp->mtx);
3742 if (len > NFSV4_SMALLSTR)
3743 free(cp, M_NFSSTRING);
3744 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3745 *cpp = cp;
3746 len = i;
3747 goto tryagain;
3748 }
3749 *retlenp = i;
3750 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3751 if (!hasampersand) {
3752 cp += usrp->lug_namelen;
3753 *cp++ = '@';
3754 NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3755 NFSD_VNET(nfsrv_dnsnamelen));
3756 }
3757 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3758 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3759 lug_numhash);
3760 mtx_unlock(&hp->mtx);
3761 NFSD_CURVNET_RESTORE();
3762 return;
3763 }
3764 }
3765 mtx_unlock(&hp->mtx);
3766 cnt++;
3767 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3768 if (ret == 0 && cnt < 2)
3769 goto tryagain;
3770 }
3771
3772 /*
3773 * No match, just return a string of digits.
3774 */
3775 tmp = gid;
3776 i = 0;
3777 while (tmp || i == 0) {
3778 tmp /= 10;
3779 i++;
3780 }
3781 len = (i > len) ? len : i;
3782 *retlenp = len;
3783 cp += (len - 1);
3784 tmp = gid;
3785 for (i = 0; i < len; i++) {
3786 *cp-- = '0' + (tmp % 10);
3787 tmp /= 10;
3788 }
3789 NFSD_CURVNET_RESTORE();
3790 return;
3791 }
3792
3793 /*
3794 * Convert a string to a gid.
3795 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3796 * return 0.
3797 * If this is called from a client side mount using AUTH_SYS and the
3798 * string is made up entirely of digits, just convert the string to
3799 * a number.
3800 */
3801 int
nfsv4_strtogid(struct nfsrv_descript * nd,u_char * str,int len,gid_t * gidp)3802 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3803 {
3804 int i;
3805 char *cp, *endstr, *str0;
3806 struct nfsusrgrp *usrp;
3807 int cnt, ret;
3808 int error = 0;
3809 gid_t tgid;
3810 struct nfsrv_lughash *hp, *hp2;
3811
3812 NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3813 if (len == 0) {
3814 error = NFSERR_BADOWNER;
3815 goto out;
3816 }
3817 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3818 str0 = str;
3819 tgid = (gid_t)strtoul(str0, &endstr, 10);
3820 if ((endstr - str0) == len) {
3821 /* A numeric string. */
3822 if ((nd->nd_flag & ND_KERBV) == 0 &&
3823 ((nd->nd_flag & ND_NFSCL) != 0 ||
3824 NFSD_VNET(nfsd_enable_stringtouid) != 0))
3825 *gidp = tgid;
3826 else
3827 error = NFSERR_BADOWNER;
3828 goto out;
3829 }
3830 /*
3831 * Look for an '@'.
3832 */
3833 cp = strchr(str0, '@');
3834 if (cp != NULL)
3835 i = (int)(cp++ - str0);
3836 else
3837 i = len;
3838
3839 cnt = 0;
3840 tryagain:
3841 if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
3842 /*
3843 * If an '@' is found and the dns name matches, search for the
3844 * name with the dns stripped off.
3845 */
3846 if (cnt == 0 && i < len && i > 0 &&
3847 (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
3848 strncasecmp(cp, NFSD_VNET(nfsrv_dnsname),
3849 NFSD_VNET(nfsrv_dnsnamelen)) == 0) {
3850 len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
3851 *(cp - 1) = '\0';
3852 }
3853
3854 /*
3855 * Check for the special case of "nogroup".
3856 */
3857 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3858 *gidp = NFSD_VNET(nfsrv_defaultgid);
3859 error = 0;
3860 goto out;
3861 }
3862
3863 hp = NFSGROUPNAMEHASH(str, len);
3864 mtx_lock(&hp->mtx);
3865 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3866 if (usrp->lug_namelen == len &&
3867 !NFSBCMP(usrp->lug_name, str, len)) {
3868 if (usrp->lug_expiry < NFSD_MONOSEC)
3869 break;
3870 hp2 = NFSGROUPHASH(usrp->lug_gid);
3871 mtx_lock(&hp2->mtx);
3872 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3873 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3874 lug_numhash);
3875 *gidp = usrp->lug_gid;
3876 mtx_unlock(&hp2->mtx);
3877 mtx_unlock(&hp->mtx);
3878 error = 0;
3879 goto out;
3880 }
3881 }
3882 mtx_unlock(&hp->mtx);
3883 cnt++;
3884 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3885 str);
3886 if (ret == 0 && cnt < 2)
3887 goto tryagain;
3888 }
3889 error = NFSERR_BADOWNER;
3890
3891 out:
3892 NFSD_CURVNET_RESTORE();
3893 NFSEXITCODE(error);
3894 return (error);
3895 }
3896
3897 /*
3898 * Set the port for the nfsuserd.
3899 */
3900 int
nfsrv_nfsuserdport(struct nfsuserd_args * nargs,NFSPROC_T * p)3901 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3902 {
3903 struct nfssockreq *rp;
3904 #ifdef INET
3905 struct sockaddr_in *ad;
3906 #endif
3907 #ifdef INET6
3908 struct sockaddr_in6 *ad6;
3909 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3910 #endif
3911 int error;
3912
3913 NFSLOCKNAMEID();
3914 if (NFSD_VNET(nfsrv_nfsuserd) != NOTRUNNING) {
3915 NFSUNLOCKNAMEID();
3916 error = EPERM;
3917 goto out;
3918 }
3919 NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
3920 /*
3921 * Set up the socket record and connect.
3922 * Set nr_client NULL before unlocking, just to ensure that no other
3923 * process/thread/core will use a bogus old value. This could only
3924 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3925 * broken.
3926 */
3927 rp = &NFSD_VNET(nfsrv_nfsuserdsock);
3928 rp->nr_client = NULL;
3929 NFSUNLOCKNAMEID();
3930 rp->nr_sotype = SOCK_DGRAM;
3931 rp->nr_soproto = IPPROTO_UDP;
3932 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3933 rp->nr_cred = NULL;
3934 rp->nr_prog = RPCPROG_NFSUSERD;
3935 error = 0;
3936 switch (nargs->nuserd_family) {
3937 #ifdef INET
3938 case AF_INET:
3939 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3940 M_WAITOK | M_ZERO);
3941 ad = (struct sockaddr_in *)rp->nr_nam;
3942 ad->sin_len = sizeof(struct sockaddr_in);
3943 ad->sin_family = AF_INET;
3944 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3945 ad->sin_port = nargs->nuserd_port;
3946 break;
3947 #endif
3948 #ifdef INET6
3949 case AF_INET6:
3950 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3951 M_WAITOK | M_ZERO);
3952 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3953 ad6->sin6_len = sizeof(struct sockaddr_in6);
3954 ad6->sin6_family = AF_INET6;
3955 ad6->sin6_addr = in6loopback;
3956 ad6->sin6_port = nargs->nuserd_port;
3957 break;
3958 #endif
3959 default:
3960 error = ENXIO;
3961 }
3962 rp->nr_vers = RPCNFSUSERD_VERS;
3963 if (error == 0)
3964 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false,
3965 &rp->nr_client);
3966 if (error == 0) {
3967 NFSLOCKNAMEID();
3968 NFSD_VNET(nfsrv_nfsuserd) = RUNNING;
3969 NFSUNLOCKNAMEID();
3970 } else {
3971 free(rp->nr_nam, M_SONAME);
3972 NFSLOCKNAMEID();
3973 NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
3974 NFSUNLOCKNAMEID();
3975 }
3976 out:
3977 NFSEXITCODE(error);
3978 return (error);
3979 }
3980
3981 /*
3982 * Delete the nfsuserd port.
3983 */
3984 void
nfsrv_nfsuserddelport(void)3985 nfsrv_nfsuserddelport(void)
3986 {
3987
3988 NFSLOCKNAMEID();
3989 if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
3990 NFSUNLOCKNAMEID();
3991 return;
3992 }
3993 NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
3994 /* Wait for all upcalls to complete. */
3995 while (NFSD_VNET(nfsrv_userdupcalls) > 0)
3996 msleep(&NFSD_VNET(nfsrv_userdupcalls), NFSNAMEIDMUTEXPTR, PVFS,
3997 "nfsupcalls", 0);
3998 NFSUNLOCKNAMEID();
3999 newnfs_disconnect(NULL, &NFSD_VNET(nfsrv_nfsuserdsock));
4000 free(NFSD_VNET(nfsrv_nfsuserdsock).nr_nam, M_SONAME);
4001 NFSLOCKNAMEID();
4002 NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
4003 NFSUNLOCKNAMEID();
4004 }
4005
4006 /*
4007 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
4008 * name<-->id cache.
4009 * Returns 0 upon success, non-zero otherwise.
4010 */
4011 static int
nfsrv_getuser(int procnum,uid_t uid,gid_t gid,char * name)4012 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
4013 {
4014 u_int32_t *tl;
4015 struct nfsrv_descript *nd;
4016 int len;
4017 struct nfsrv_descript nfsd;
4018 struct ucred *cred;
4019 int error;
4020
4021 NFSLOCKNAMEID();
4022 if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
4023 NFSUNLOCKNAMEID();
4024 error = EPERM;
4025 goto out;
4026 }
4027 /*
4028 * Maintain a count of upcalls in progress, so that nfsrv_X()
4029 * can wait until no upcalls are in progress.
4030 */
4031 NFSD_VNET(nfsrv_userdupcalls)++;
4032 NFSUNLOCKNAMEID();
4033 KASSERT(NFSD_VNET(nfsrv_userdupcalls) > 0,
4034 ("nfsrv_getuser: non-positive upcalls"));
4035 nd = &nfsd;
4036 cred = newnfs_getcred();
4037 nd->nd_flag = ND_GSSINITREPLY;
4038 nfsrvd_rephead(nd);
4039
4040 nd->nd_procnum = procnum;
4041 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
4042 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4043 if (procnum == RPCNFSUSERD_GETUID)
4044 *tl = txdr_unsigned(uid);
4045 else
4046 *tl = txdr_unsigned(gid);
4047 } else {
4048 len = strlen(name);
4049 (void) nfsm_strtom(nd, name, len);
4050 }
4051 error = newnfs_request(nd, NULL, NULL, &NFSD_VNET(nfsrv_nfsuserdsock),
4052 NULL, NULL, cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0,
4053 NULL, NULL);
4054 NFSLOCKNAMEID();
4055 if (--NFSD_VNET(nfsrv_userdupcalls) == 0 &&
4056 NFSD_VNET(nfsrv_nfsuserd) == STARTSTOP)
4057 wakeup(&NFSD_VNET(nfsrv_userdupcalls));
4058 NFSUNLOCKNAMEID();
4059 NFSFREECRED(cred);
4060 if (!error) {
4061 m_freem(nd->nd_mrep);
4062 error = nd->nd_repstat;
4063 }
4064 out:
4065 NFSEXITCODE(error);
4066 return (error);
4067 }
4068
4069 /*
4070 * This function is called from the nfssvc(2) system call, to update the
4071 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
4072 */
4073 int
nfssvc_idname(struct nfsd_idargs * nidp)4074 nfssvc_idname(struct nfsd_idargs *nidp)
4075 {
4076 struct nfsusrgrp *nusrp, *usrp, *newusrp;
4077 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
4078 int i, group_locked, groupname_locked, user_locked, username_locked;
4079 int error = 0;
4080 u_char *cp;
4081 gid_t *grps;
4082 struct ucred *cr;
4083 static int onethread = 0;
4084 static time_t lasttime = 0;
4085
4086 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
4087 error = EINVAL;
4088 goto out;
4089 }
4090 if (nidp->nid_flag & NFSID_INITIALIZE) {
4091 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
4092 error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
4093 if (error != 0) {
4094 free(cp, M_NFSSTRING);
4095 goto out;
4096 }
4097 if (atomic_cmpset_acq_int(&NFSD_VNET(nfsrv_dnsnamelen), 0, 0) ==
4098 0) {
4099 /*
4100 * Free up all the old stuff and reinitialize hash
4101 * lists. All mutexes for both lists must be locked,
4102 * with the user/group name ones before the uid/gid
4103 * ones, to avoid a LOR.
4104 */
4105 for (i = 0; i < nfsrv_lughashsize; i++)
4106 mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4107 for (i = 0; i < nfsrv_lughashsize; i++)
4108 mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
4109 for (i = 0; i < nfsrv_lughashsize; i++)
4110 TAILQ_FOREACH_SAFE(usrp,
4111 &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash, nusrp)
4112 nfsrv_removeuser(usrp, 1);
4113 for (i = 0; i < nfsrv_lughashsize; i++)
4114 mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
4115 for (i = 0; i < nfsrv_lughashsize; i++)
4116 mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4117 for (i = 0; i < nfsrv_lughashsize; i++)
4118 mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4119 for (i = 0; i < nfsrv_lughashsize; i++)
4120 mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4121 for (i = 0; i < nfsrv_lughashsize; i++)
4122 TAILQ_FOREACH_SAFE(usrp,
4123 &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
4124 nusrp)
4125 nfsrv_removeuser(usrp, 0);
4126 for (i = 0; i < nfsrv_lughashsize; i++)
4127 mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4128 for (i = 0; i < nfsrv_lughashsize; i++)
4129 mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4130 free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
4131 NFSD_VNET(nfsrv_dnsname) = NULL;
4132 }
4133 if (NFSD_VNET(nfsuserhash) == NULL) {
4134 /* Allocate the hash tables. */
4135 NFSD_VNET(nfsuserhash) = malloc(sizeof(struct nfsrv_lughash) *
4136 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
4137 M_ZERO);
4138 for (i = 0; i < nfsrv_lughashsize; i++)
4139 mtx_init(&NFSD_VNET(nfsuserhash)[i].mtx, "nfsuidhash",
4140 NULL, MTX_DEF | MTX_DUPOK);
4141 NFSD_VNET(nfsusernamehash) = malloc(sizeof(struct nfsrv_lughash) *
4142 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
4143 M_ZERO);
4144 for (i = 0; i < nfsrv_lughashsize; i++)
4145 mtx_init(&NFSD_VNET(nfsusernamehash)[i].mtx,
4146 "nfsusrhash", NULL, MTX_DEF |
4147 MTX_DUPOK);
4148 NFSD_VNET(nfsgrouphash) = 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(nfsgrouphash)[i].mtx, "nfsgidhash",
4153 NULL, MTX_DEF | MTX_DUPOK);
4154 NFSD_VNET(nfsgroupnamehash) = 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(nfsgroupnamehash)[i].mtx,
4159 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
4160 }
4161 /* (Re)initialize the list heads. */
4162 for (i = 0; i < nfsrv_lughashsize; i++)
4163 TAILQ_INIT(&NFSD_VNET(nfsuserhash)[i].lughead);
4164 for (i = 0; i < nfsrv_lughashsize; i++)
4165 TAILQ_INIT(&NFSD_VNET(nfsusernamehash)[i].lughead);
4166 for (i = 0; i < nfsrv_lughashsize; i++)
4167 TAILQ_INIT(&NFSD_VNET(nfsgrouphash)[i].lughead);
4168 for (i = 0; i < nfsrv_lughashsize; i++)
4169 TAILQ_INIT(&NFSD_VNET(nfsgroupnamehash)[i].lughead);
4170
4171 /*
4172 * Put name in "DNS" string.
4173 */
4174 NFSD_VNET(nfsrv_dnsname) = cp;
4175 NFSD_VNET(nfsrv_defaultuid) = nidp->nid_uid;
4176 NFSD_VNET(nfsrv_defaultgid) = nidp->nid_gid;
4177 NFSD_VNET(nfsrv_usercnt) = 0;
4178 NFSD_VNET(nfsrv_usermax) = nidp->nid_usermax;
4179 atomic_store_rel_int(&NFSD_VNET(nfsrv_dnsnamelen),
4180 nidp->nid_namelen);
4181 goto out;
4182 }
4183
4184 /*
4185 * malloc the new one now, so any potential sleep occurs before
4186 * manipulation of the lists.
4187 */
4188 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
4189 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
4190 error = copyin(nidp->nid_name, newusrp->lug_name,
4191 nidp->nid_namelen);
4192 if (error == 0 && nidp->nid_ngroup > 0 &&
4193 (nidp->nid_flag & NFSID_ADDUID) != 0) {
4194 grps = NULL;
4195 if (nidp->nid_ngroup > NGROUPS_MAX)
4196 error = EINVAL;
4197 if (error == 0) {
4198 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
4199 M_WAITOK);
4200 error = copyin(nidp->nid_grps, grps,
4201 sizeof(gid_t) * nidp->nid_ngroup);
4202 }
4203 if (error == 0) {
4204 /*
4205 * Create a credential just like svc_getcred(),
4206 * but using the group list provided.
4207 */
4208 cr = crget();
4209 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
4210 crsetgroups_and_egid(cr, nidp->nid_ngroup, grps,
4211 GID_NOGROUP);
4212 cr->cr_rgid = cr->cr_svgid = cr->cr_gid;
4213 cr->cr_prison = curthread->td_ucred->cr_prison;
4214 prison_hold(cr->cr_prison);
4215 #ifdef MAC
4216 mac_cred_associate_nfsd(cr);
4217 #endif
4218 newusrp->lug_cred = cr;
4219 }
4220 free(grps, M_TEMP);
4221 }
4222 if (error) {
4223 free(newusrp, M_NFSUSERGROUP);
4224 goto out;
4225 }
4226 newusrp->lug_namelen = nidp->nid_namelen;
4227
4228 /*
4229 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
4230 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
4231 * The flags user_locked, username_locked, group_locked and
4232 * groupname_locked are set to indicate all of those hash lists are
4233 * locked. hp_name != NULL and hp_idnum != NULL indicates that
4234 * the respective one mutex is locked.
4235 */
4236 user_locked = username_locked = group_locked = groupname_locked = 0;
4237 hp_name = hp_idnum = NULL;
4238
4239 /*
4240 * Delete old entries, as required.
4241 */
4242 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
4243 /* Must lock all username hash lists first, to avoid a LOR. */
4244 for (i = 0; i < nfsrv_lughashsize; i++)
4245 mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4246 username_locked = 1;
4247 hp_idnum = NFSUSERHASH(nidp->nid_uid);
4248 mtx_lock(&hp_idnum->mtx);
4249 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
4250 nusrp) {
4251 if (usrp->lug_uid == nidp->nid_uid)
4252 nfsrv_removeuser(usrp, 1);
4253 }
4254 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
4255 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
4256 newusrp->lug_namelen);
4257 mtx_lock(&hp_name->mtx);
4258 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
4259 nusrp) {
4260 if (usrp->lug_namelen == newusrp->lug_namelen &&
4261 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
4262 usrp->lug_namelen)) {
4263 thp = NFSUSERHASH(usrp->lug_uid);
4264 mtx_lock(&thp->mtx);
4265 nfsrv_removeuser(usrp, 1);
4266 mtx_unlock(&thp->mtx);
4267 }
4268 }
4269 hp_idnum = NFSUSERHASH(nidp->nid_uid);
4270 mtx_lock(&hp_idnum->mtx);
4271 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
4272 /* Must lock all groupname hash lists first, to avoid a LOR. */
4273 for (i = 0; i < nfsrv_lughashsize; i++)
4274 mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4275 groupname_locked = 1;
4276 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
4277 mtx_lock(&hp_idnum->mtx);
4278 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
4279 nusrp) {
4280 if (usrp->lug_gid == nidp->nid_gid)
4281 nfsrv_removeuser(usrp, 0);
4282 }
4283 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
4284 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
4285 newusrp->lug_namelen);
4286 mtx_lock(&hp_name->mtx);
4287 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
4288 nusrp) {
4289 if (usrp->lug_namelen == newusrp->lug_namelen &&
4290 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
4291 usrp->lug_namelen)) {
4292 thp = NFSGROUPHASH(usrp->lug_gid);
4293 mtx_lock(&thp->mtx);
4294 nfsrv_removeuser(usrp, 0);
4295 mtx_unlock(&thp->mtx);
4296 }
4297 }
4298 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
4299 mtx_lock(&hp_idnum->mtx);
4300 }
4301
4302 /*
4303 * Now, we can add the new one.
4304 */
4305 if (nidp->nid_usertimeout)
4306 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
4307 else
4308 newusrp->lug_expiry = NFSD_MONOSEC + 5;
4309 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
4310 newusrp->lug_uid = nidp->nid_uid;
4311 thp = NFSUSERHASH(newusrp->lug_uid);
4312 mtx_assert(&thp->mtx, MA_OWNED);
4313 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4314 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4315 mtx_assert(&thp->mtx, MA_OWNED);
4316 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4317 atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
4318 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
4319 newusrp->lug_gid = nidp->nid_gid;
4320 thp = NFSGROUPHASH(newusrp->lug_gid);
4321 mtx_assert(&thp->mtx, MA_OWNED);
4322 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4323 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4324 mtx_assert(&thp->mtx, MA_OWNED);
4325 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4326 atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
4327 } else {
4328 if (newusrp->lug_cred != NULL)
4329 crfree(newusrp->lug_cred);
4330 free(newusrp, M_NFSUSERGROUP);
4331 }
4332
4333 /*
4334 * Once per second, allow one thread to trim the cache.
4335 */
4336 if (lasttime < NFSD_MONOSEC &&
4337 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
4338 /*
4339 * First, unlock the single mutexes, so that all entries
4340 * can be locked and any LOR is avoided.
4341 */
4342 if (hp_name != NULL) {
4343 mtx_unlock(&hp_name->mtx);
4344 hp_name = NULL;
4345 }
4346 if (hp_idnum != NULL) {
4347 mtx_unlock(&hp_idnum->mtx);
4348 hp_idnum = NULL;
4349 }
4350
4351 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4352 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4353 if (username_locked == 0) {
4354 for (i = 0; i < nfsrv_lughashsize; i++)
4355 mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4356 username_locked = 1;
4357 }
4358 KASSERT(user_locked == 0,
4359 ("nfssvc_idname: user_locked"));
4360 for (i = 0; i < nfsrv_lughashsize; i++)
4361 mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
4362 user_locked = 1;
4363 for (i = 0; i < nfsrv_lughashsize; i++) {
4364 TAILQ_FOREACH_SAFE(usrp,
4365 &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash,
4366 nusrp)
4367 if (usrp->lug_expiry < NFSD_MONOSEC)
4368 nfsrv_removeuser(usrp, 1);
4369 }
4370 for (i = 0; i < nfsrv_lughashsize; i++) {
4371 /*
4372 * Trim the cache using an approximate LRU
4373 * algorithm. This code deletes the least
4374 * recently used entry on each hash list.
4375 */
4376 if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
4377 break;
4378 usrp = TAILQ_FIRST(&NFSD_VNET(nfsuserhash)[i].lughead);
4379 if (usrp != NULL)
4380 nfsrv_removeuser(usrp, 1);
4381 }
4382 } else {
4383 if (groupname_locked == 0) {
4384 for (i = 0; i < nfsrv_lughashsize; i++)
4385 mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4386 groupname_locked = 1;
4387 }
4388 KASSERT(group_locked == 0,
4389 ("nfssvc_idname: group_locked"));
4390 for (i = 0; i < nfsrv_lughashsize; i++)
4391 mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4392 group_locked = 1;
4393 for (i = 0; i < nfsrv_lughashsize; i++) {
4394 TAILQ_FOREACH_SAFE(usrp,
4395 &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
4396 nusrp)
4397 if (usrp->lug_expiry < NFSD_MONOSEC)
4398 nfsrv_removeuser(usrp, 0);
4399 }
4400 for (i = 0; i < nfsrv_lughashsize; i++) {
4401 /*
4402 * Trim the cache using an approximate LRU
4403 * algorithm. This code deletes the least
4404 * recently user entry on each hash list.
4405 */
4406 if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
4407 break;
4408 usrp = TAILQ_FIRST(&NFSD_VNET(nfsgrouphash)[i].lughead);
4409 if (usrp != NULL)
4410 nfsrv_removeuser(usrp, 0);
4411 }
4412 }
4413 lasttime = NFSD_MONOSEC;
4414 atomic_store_rel_int(&onethread, 0);
4415 }
4416
4417 /* Now, unlock all locked mutexes. */
4418 if (hp_idnum != NULL)
4419 mtx_unlock(&hp_idnum->mtx);
4420 if (hp_name != NULL)
4421 mtx_unlock(&hp_name->mtx);
4422 if (user_locked != 0)
4423 for (i = 0; i < nfsrv_lughashsize; i++)
4424 mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
4425 if (username_locked != 0)
4426 for (i = 0; i < nfsrv_lughashsize; i++)
4427 mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4428 if (group_locked != 0)
4429 for (i = 0; i < nfsrv_lughashsize; i++)
4430 mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4431 if (groupname_locked != 0)
4432 for (i = 0; i < nfsrv_lughashsize; i++)
4433 mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4434 out:
4435 NFSEXITCODE(error);
4436 return (error);
4437 }
4438
4439 /*
4440 * Remove a user/group name element.
4441 */
4442 static void
nfsrv_removeuser(struct nfsusrgrp * usrp,int isuser)4443 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4444 {
4445 struct nfsrv_lughash *hp;
4446
4447 if (isuser != 0) {
4448 hp = NFSUSERHASH(usrp->lug_uid);
4449 mtx_assert(&hp->mtx, MA_OWNED);
4450 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4451 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4452 mtx_assert(&hp->mtx, MA_OWNED);
4453 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4454 } else {
4455 hp = NFSGROUPHASH(usrp->lug_gid);
4456 mtx_assert(&hp->mtx, MA_OWNED);
4457 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4458 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4459 mtx_assert(&hp->mtx, MA_OWNED);
4460 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4461 }
4462 atomic_add_int(&NFSD_VNET(nfsrv_usercnt), -1);
4463 if (usrp->lug_cred != NULL)
4464 crfree(usrp->lug_cred);
4465 free(usrp, M_NFSUSERGROUP);
4466 }
4467
4468 /*
4469 * Free up all the allocations related to the name<-->id cache.
4470 * This function should only be called when the nfsuserd daemon isn't
4471 * running, since it doesn't do any locking.
4472 * This function is meant to be called when a vnet jail is destroyed.
4473 */
4474 void
nfsrv_cleanusergroup(void)4475 nfsrv_cleanusergroup(void)
4476 {
4477 struct nfsrv_lughash *hp, *hp2;
4478 struct nfsusrgrp *nusrp, *usrp;
4479 int i;
4480
4481 if (NFSD_VNET(nfsuserhash) == NULL)
4482 return;
4483
4484 for (i = 0; i < nfsrv_lughashsize; i++) {
4485 hp = &NFSD_VNET(nfsuserhash)[i];
4486 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4487 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4488 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4489 usrp->lug_namelen);
4490 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4491 if (usrp->lug_cred != NULL)
4492 crfree(usrp->lug_cred);
4493 free(usrp, M_NFSUSERGROUP);
4494 }
4495 hp = &NFSD_VNET(nfsgrouphash)[i];
4496 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4497 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4498 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4499 usrp->lug_namelen);
4500 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4501 if (usrp->lug_cred != NULL)
4502 crfree(usrp->lug_cred);
4503 free(usrp, M_NFSUSERGROUP);
4504 }
4505 mtx_destroy(&NFSD_VNET(nfsuserhash)[i].mtx);
4506 mtx_destroy(&NFSD_VNET(nfsusernamehash)[i].mtx);
4507 mtx_destroy(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4508 mtx_destroy(&NFSD_VNET(nfsgrouphash)[i].mtx);
4509 }
4510 free(NFSD_VNET(nfsuserhash), M_NFSUSERGROUP);
4511 free(NFSD_VNET(nfsusernamehash), M_NFSUSERGROUP);
4512 free(NFSD_VNET(nfsgrouphash), M_NFSUSERGROUP);
4513 free(NFSD_VNET(nfsgroupnamehash), M_NFSUSERGROUP);
4514 free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
4515 }
4516
4517 /*
4518 * This function scans a byte string and checks for UTF-8 compliance.
4519 * It returns 0 if it conforms and NFSERR_INVAL if not.
4520 */
4521 int
nfsrv_checkutf8(u_int8_t * cp,int len)4522 nfsrv_checkutf8(u_int8_t *cp, int len)
4523 {
4524 u_int32_t val = 0x0;
4525 int cnt = 0, gotd = 0, shift = 0;
4526 u_int8_t byte;
4527 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4528 int error = 0;
4529
4530 /*
4531 * Here are what the variables are used for:
4532 * val - the calculated value of a multibyte char, used to check
4533 * that it was coded with the correct range
4534 * cnt - the number of 10xxxxxx bytes to follow
4535 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4536 * shift - lower order bits of range (ie. "val >> shift" should
4537 * not be 0, in other words, dividing by the lower bound
4538 * of the range should get a non-zero value)
4539 * byte - used to calculate cnt
4540 */
4541 while (len > 0) {
4542 if (cnt > 0) {
4543 /* This handles the 10xxxxxx bytes */
4544 if ((*cp & 0xc0) != 0x80 ||
4545 (gotd && (*cp & 0x20))) {
4546 error = NFSERR_INVAL;
4547 goto out;
4548 }
4549 gotd = 0;
4550 val <<= 6;
4551 val |= (*cp & 0x3f);
4552 cnt--;
4553 if (cnt == 0 && (val >> shift) == 0x0) {
4554 error = NFSERR_INVAL;
4555 goto out;
4556 }
4557 } else if (*cp & 0x80) {
4558 /* first byte of multi byte char */
4559 byte = *cp;
4560 while ((byte & 0x40) && cnt < 6) {
4561 cnt++;
4562 byte <<= 1;
4563 }
4564 if (cnt == 0 || cnt == 6) {
4565 error = NFSERR_INVAL;
4566 goto out;
4567 }
4568 val = (*cp & (0x3f >> cnt));
4569 shift = utf8_shift[cnt - 1];
4570 if (cnt == 2 && val == 0xd)
4571 /* Check for the 0xd800-0xdfff case */
4572 gotd = 1;
4573 }
4574 cp++;
4575 len--;
4576 }
4577 if (cnt > 0)
4578 error = NFSERR_INVAL;
4579
4580 out:
4581 NFSEXITCODE(error);
4582 return (error);
4583 }
4584
4585 /*
4586 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4587 * strings, one with the root path in it and the other with the list of
4588 * locations. The list is in the same format as is found in nfr_refs.
4589 * It is a "," separated list of entries, where each of them is of the
4590 * form <server>:<rootpath>. For example
4591 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4592 * The nilp argument is set to 1 for the special case of a null fs_root
4593 * and an empty server list.
4594 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4595 * number of xdr bytes parsed in sump.
4596 */
4597 static int
nfsrv_getrefstr(struct nfsrv_descript * nd,u_char ** fsrootp,u_char ** srvp,int * sump,int * nilp)4598 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4599 int *sump, int *nilp)
4600 {
4601 u_int32_t *tl;
4602 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4603 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4604 struct list {
4605 SLIST_ENTRY(list) next;
4606 int len;
4607 u_char host[1];
4608 } *lsp, *nlsp;
4609 SLIST_HEAD(, list) head;
4610
4611 *fsrootp = NULL;
4612 *srvp = NULL;
4613 *nilp = 0;
4614
4615 /*
4616 * Get the fs_root path and check for the special case of null path
4617 * and 0 length server list.
4618 */
4619 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4620 len = fxdr_unsigned(int, *tl);
4621 if (len < 0 || len > 10240) {
4622 error = NFSERR_BADXDR;
4623 goto nfsmout;
4624 }
4625 if (len == 0) {
4626 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4627 if (*tl != 0) {
4628 error = NFSERR_BADXDR;
4629 goto nfsmout;
4630 }
4631 *nilp = 1;
4632 *sump = 2 * NFSX_UNSIGNED;
4633 error = 0;
4634 goto nfsmout;
4635 }
4636 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4637 error = nfsrv_mtostr(nd, cp, len);
4638 if (!error) {
4639 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4640 cnt = fxdr_unsigned(int, *tl);
4641 if (cnt <= 0)
4642 error = NFSERR_BADXDR;
4643 }
4644 if (error)
4645 goto nfsmout;
4646
4647 /*
4648 * Now, loop through the location list and make up the srvlist.
4649 */
4650 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4651 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4652 slen = 1024;
4653 siz = 0;
4654 for (i = 0; i < cnt; i++) {
4655 SLIST_INIT(&head);
4656 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4657 nsrv = fxdr_unsigned(int, *tl);
4658 if (nsrv <= 0) {
4659 error = NFSERR_BADXDR;
4660 goto nfsmout;
4661 }
4662
4663 /*
4664 * Handle the first server by putting it in the srvstr.
4665 */
4666 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4667 len = fxdr_unsigned(int, *tl);
4668 if (len <= 0 || len > 1024) {
4669 error = NFSERR_BADXDR;
4670 goto nfsmout;
4671 }
4672 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4673 if (cp3 != cp2) {
4674 *cp3++ = ',';
4675 siz++;
4676 }
4677 error = nfsrv_mtostr(nd, cp3, len);
4678 if (error)
4679 goto nfsmout;
4680 cp3 += len;
4681 *cp3++ = ':';
4682 siz += (len + 1);
4683 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4684 for (j = 1; j < nsrv; j++) {
4685 /*
4686 * Yuck, put them in an slist and process them later.
4687 */
4688 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4689 len = fxdr_unsigned(int, *tl);
4690 if (len <= 0 || len > 1024) {
4691 error = NFSERR_BADXDR;
4692 goto nfsmout;
4693 }
4694 lsp = (struct list *)malloc(sizeof (struct list)
4695 + len, M_TEMP, M_WAITOK);
4696 error = nfsrv_mtostr(nd, lsp->host, len);
4697 if (error)
4698 goto nfsmout;
4699 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4700 lsp->len = len;
4701 SLIST_INSERT_HEAD(&head, lsp, next);
4702 }
4703
4704 /*
4705 * Finally, we can get the path.
4706 */
4707 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4708 len = fxdr_unsigned(int, *tl);
4709 if (len <= 0 || len > 1024) {
4710 error = NFSERR_BADXDR;
4711 goto nfsmout;
4712 }
4713 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4714 error = nfsrv_mtostr(nd, cp3, len);
4715 if (error)
4716 goto nfsmout;
4717 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4718 str = cp3;
4719 stringlen = len;
4720 cp3 += len;
4721 siz += len;
4722 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4723 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4724 &cp2, &cp3, &slen);
4725 *cp3++ = ',';
4726 NFSBCOPY(lsp->host, cp3, lsp->len);
4727 cp3 += lsp->len;
4728 *cp3++ = ':';
4729 NFSBCOPY(str, cp3, stringlen);
4730 cp3 += stringlen;
4731 *cp3 = '\0';
4732 siz += (lsp->len + stringlen + 2);
4733 free(lsp, M_TEMP);
4734 }
4735 }
4736 *fsrootp = cp;
4737 *srvp = cp2;
4738 *sump = xdrsum;
4739 NFSEXITCODE2(0, nd);
4740 return (0);
4741 nfsmout:
4742 if (cp != NULL)
4743 free(cp, M_NFSSTRING);
4744 if (cp2 != NULL)
4745 free(cp2, M_NFSSTRING);
4746 NFSEXITCODE2(error, nd);
4747 return (error);
4748 }
4749
4750 /*
4751 * Make the malloc'd space large enough. This is a pain, but the xdr
4752 * doesn't set an upper bound on the side, so...
4753 */
4754 static void
nfsrv_refstrbigenough(int siz,u_char ** cpp,u_char ** cpp2,int * slenp)4755 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4756 {
4757 u_char *cp;
4758 int i;
4759
4760 if (siz <= *slenp)
4761 return;
4762 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4763 NFSBCOPY(*cpp, cp, *slenp);
4764 free(*cpp, M_NFSSTRING);
4765 i = *cpp2 - *cpp;
4766 *cpp = cp;
4767 *cpp2 = cp + i;
4768 *slenp = siz + 1024;
4769 }
4770
4771 /*
4772 * Initialize the reply header data structures.
4773 */
4774 void
nfsrvd_rephead(struct nfsrv_descript * nd)4775 nfsrvd_rephead(struct nfsrv_descript *nd)
4776 {
4777 struct mbuf *mreq;
4778
4779 if ((nd->nd_flag & ND_EXTPG) != 0) {
4780 mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4781 nd->nd_mreq = nd->nd_mb = mreq;
4782 nd->nd_bpos = (char *)(void *)
4783 PHYS_TO_DMAP(mreq->m_epg_pa[0]);
4784 nd->nd_bextpg = 0;
4785 nd->nd_bextpgsiz = PAGE_SIZE;
4786 } else {
4787 /*
4788 * If this is a big reply, use a cluster.
4789 */
4790 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4791 nfs_bigreply[nd->nd_procnum]) {
4792 NFSMCLGET(mreq, M_WAITOK);
4793 nd->nd_mreq = mreq;
4794 nd->nd_mb = mreq;
4795 } else {
4796 NFSMGET(mreq);
4797 nd->nd_mreq = mreq;
4798 nd->nd_mb = mreq;
4799 }
4800 nd->nd_bpos = mtod(mreq, char *);
4801 mreq->m_len = 0;
4802 }
4803
4804 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4805 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4806 }
4807
4808 /*
4809 * Lock a socket against others.
4810 * Currently used to serialize connect/disconnect attempts.
4811 */
4812 int
newnfs_sndlock(int * flagp)4813 newnfs_sndlock(int *flagp)
4814 {
4815 struct timespec ts;
4816
4817 NFSLOCKSOCK();
4818 while (*flagp & NFSR_SNDLOCK) {
4819 *flagp |= NFSR_WANTSND;
4820 ts.tv_sec = 0;
4821 ts.tv_nsec = 0;
4822 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4823 PVFS, "nfsndlck", &ts);
4824 }
4825 *flagp |= NFSR_SNDLOCK;
4826 NFSUNLOCKSOCK();
4827 return (0);
4828 }
4829
4830 /*
4831 * Unlock the stream socket for others.
4832 */
4833 void
newnfs_sndunlock(int * flagp)4834 newnfs_sndunlock(int *flagp)
4835 {
4836
4837 NFSLOCKSOCK();
4838 if ((*flagp & NFSR_SNDLOCK) == 0)
4839 panic("nfs sndunlock");
4840 *flagp &= ~NFSR_SNDLOCK;
4841 if (*flagp & NFSR_WANTSND) {
4842 *flagp &= ~NFSR_WANTSND;
4843 wakeup((caddr_t)flagp);
4844 }
4845 NFSUNLOCKSOCK();
4846 }
4847
4848 int
nfsv4_getipaddr(struct nfsrv_descript * nd,struct sockaddr_in * sin,struct sockaddr_in6 * sin6,sa_family_t * saf,int * isudp)4849 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4850 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4851 {
4852 struct in_addr saddr;
4853 uint32_t portnum, *tl;
4854 int i, j, k;
4855 sa_family_t af = AF_UNSPEC;
4856 char addr[64], protocol[5], *cp;
4857 int cantparse = 0, error = 0;
4858 uint16_t portv;
4859
4860 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4861 i = fxdr_unsigned(int, *tl);
4862 if (i >= 3 && i <= 4) {
4863 error = nfsrv_mtostr(nd, protocol, i);
4864 if (error)
4865 goto nfsmout;
4866 if (strcmp(protocol, "tcp") == 0) {
4867 af = AF_INET;
4868 *isudp = 0;
4869 } else if (strcmp(protocol, "udp") == 0) {
4870 af = AF_INET;
4871 *isudp = 1;
4872 } else if (strcmp(protocol, "tcp6") == 0) {
4873 af = AF_INET6;
4874 *isudp = 0;
4875 } else if (strcmp(protocol, "udp6") == 0) {
4876 af = AF_INET6;
4877 *isudp = 1;
4878 } else
4879 cantparse = 1;
4880 } else {
4881 cantparse = 1;
4882 if (i > 0) {
4883 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4884 if (error)
4885 goto nfsmout;
4886 }
4887 }
4888 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4889 i = fxdr_unsigned(int, *tl);
4890 if (i < 0) {
4891 error = NFSERR_BADXDR;
4892 goto nfsmout;
4893 } else if (cantparse == 0 && i >= 11 && i < 64) {
4894 /*
4895 * The shortest address is 11chars and the longest is < 64.
4896 */
4897 error = nfsrv_mtostr(nd, addr, i);
4898 if (error)
4899 goto nfsmout;
4900
4901 /* Find the port# at the end and extract that. */
4902 i = strlen(addr);
4903 k = 0;
4904 cp = &addr[i - 1];
4905 /* Count back two '.'s from end to get port# field. */
4906 for (j = 0; j < i; j++) {
4907 if (*cp == '.') {
4908 k++;
4909 if (k == 2)
4910 break;
4911 }
4912 cp--;
4913 }
4914 if (k == 2) {
4915 /*
4916 * The NFSv4 port# is appended as .N.N, where N is
4917 * a decimal # in the range 0-255, just like an inet4
4918 * address. Cheat and use inet_aton(), which will
4919 * return a Class A address and then shift the high
4920 * order 8bits over to convert it to the port#.
4921 */
4922 *cp++ = '\0';
4923 if (inet_aton(cp, &saddr) == 1) {
4924 portnum = ntohl(saddr.s_addr);
4925 portv = (uint16_t)((portnum >> 16) |
4926 (portnum & 0xff));
4927 } else
4928 cantparse = 1;
4929 } else
4930 cantparse = 1;
4931 if (cantparse == 0) {
4932 if (af == AF_INET) {
4933 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4934 sin->sin_len = sizeof(*sin);
4935 sin->sin_family = AF_INET;
4936 sin->sin_port = htons(portv);
4937 *saf = af;
4938 return (0);
4939 }
4940 } else {
4941 if (inet_pton(af, addr, &sin6->sin6_addr)
4942 == 1) {
4943 sin6->sin6_len = sizeof(*sin6);
4944 sin6->sin6_family = AF_INET6;
4945 sin6->sin6_port = htons(portv);
4946 *saf = af;
4947 return (0);
4948 }
4949 }
4950 }
4951 } else {
4952 if (i > 0) {
4953 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4954 if (error)
4955 goto nfsmout;
4956 }
4957 }
4958 error = EPERM;
4959 nfsmout:
4960 return (error);
4961 }
4962
4963 /*
4964 * Handle an NFSv4.1 Sequence request for the session.
4965 * If reply != NULL, use it to return the cached reply, as required.
4966 * The client gets a cached reply via this call for callbacks, however the
4967 * server gets a cached reply via the nfsv4_seqsess_cacherep() call.
4968 */
4969 int
nfsv4_seqsession(uint32_t seqid,uint32_t slotid,uint32_t highslot,struct nfsslot * slots,struct mbuf ** reply,uint16_t maxslot)4970 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4971 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4972 {
4973 struct mbuf *m;
4974 int error;
4975
4976 error = 0;
4977 if (reply != NULL)
4978 *reply = NULL;
4979 if (slotid > maxslot)
4980 return (NFSERR_BADSLOT);
4981 if (seqid == slots[slotid].nfssl_seq) {
4982 /* A retry. */
4983 if (slots[slotid].nfssl_inprog != 0)
4984 error = NFSERR_DELAY;
4985 else if (slots[slotid].nfssl_reply != NULL) {
4986 if (reply != NULL) {
4987 m = m_copym(slots[slotid].nfssl_reply, 0,
4988 M_COPYALL, M_NOWAIT);
4989 if (m != NULL)
4990 *reply = m;
4991 else {
4992 *reply = slots[slotid].nfssl_reply;
4993 slots[slotid].nfssl_reply = NULL;
4994 }
4995 }
4996 slots[slotid].nfssl_inprog = 1;
4997 error = NFSERR_REPLYFROMCACHE;
4998 } else
4999 /* No reply cached, so just do it. */
5000 slots[slotid].nfssl_inprog = 1;
5001 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
5002 if (slots[slotid].nfssl_reply != NULL)
5003 m_freem(slots[slotid].nfssl_reply);
5004 slots[slotid].nfssl_reply = NULL;
5005 slots[slotid].nfssl_inprog = 1;
5006 slots[slotid].nfssl_seq++;
5007 } else
5008 error = NFSERR_SEQMISORDERED;
5009 return (error);
5010 }
5011
5012 /*
5013 * Cache this reply for the slot.
5014 * Use the "rep" argument to return the cached reply if repstat is set to
5015 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
5016 */
5017 void
nfsv4_seqsess_cacherep(uint32_t slotid,struct nfsslot * slots,int repstat,struct mbuf ** rep)5018 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
5019 struct mbuf **rep)
5020 {
5021 struct mbuf *m;
5022
5023 if (repstat == NFSERR_REPLYFROMCACHE) {
5024 if (slots[slotid].nfssl_reply != NULL) {
5025 /*
5026 * We cannot sleep here, but copy will usually
5027 * succeed.
5028 */
5029 m = m_copym(slots[slotid].nfssl_reply, 0, M_COPYALL,
5030 M_NOWAIT);
5031 if (m != NULL)
5032 *rep = m;
5033 else {
5034 /*
5035 * Multiple retries would be extremely rare,
5036 * so using the cached reply will likely
5037 * be ok.
5038 */
5039 *rep = slots[slotid].nfssl_reply;
5040 slots[slotid].nfssl_reply = NULL;
5041 }
5042 } else
5043 *rep = NULL;
5044 } else {
5045 if (slots[slotid].nfssl_reply != NULL)
5046 m_freem(slots[slotid].nfssl_reply);
5047 slots[slotid].nfssl_reply = *rep;
5048 }
5049 slots[slotid].nfssl_inprog = 0;
5050 }
5051
5052 /*
5053 * Generate the xdr for an NFSv4.1 Sequence Operation.
5054 */
5055 static void
nfsv4_setsequence(struct nfsmount * nmp,struct nfsrv_descript * nd,struct nfsclsession * sep,bool dont_replycache,struct ucred * cred)5056 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
5057 struct nfsclsession *sep, bool dont_replycache, struct ucred *cred)
5058 {
5059 uint32_t *tl, slotseq = 0;
5060 int error, maxslot, slotpos;
5061 uint8_t sessionid[NFSX_V4SESSIONID];
5062
5063 if (cred != NULL) {
5064 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
5065 &slotseq, sessionid, false);
5066 if (error == NFSERR_SEQMISORDERED) {
5067 /* If all slots are bad, Destroy the session. */
5068 nfsrpc_destroysession(nmp, sep, cred, curthread);
5069 }
5070 } else
5071 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
5072 &slotseq, sessionid, true);
5073 nd->nd_maxreq = sep->nfsess_maxreq;
5074 nd->nd_maxresp = sep->nfsess_maxresp;
5075
5076 /* Build the Sequence arguments. */
5077 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
5078 nd->nd_sequence = tl;
5079 bcopy(sessionid, tl, NFSX_V4SESSIONID);
5080 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
5081 nd->nd_slotseq = tl;
5082 if (error == 0) {
5083 nd->nd_flag |= ND_HASSLOTID;
5084 nd->nd_slotid = slotpos;
5085 *tl++ = txdr_unsigned(slotseq);
5086 *tl++ = txdr_unsigned(slotpos);
5087 *tl++ = txdr_unsigned(maxslot);
5088 if (!dont_replycache)
5089 *tl = newnfs_true;
5090 else
5091 *tl = newnfs_false;
5092 } else {
5093 /*
5094 * There are two errors and the rest of the session can
5095 * just be zeros.
5096 * NFSERR_BADSESSION: This bad session should just generate
5097 * the same error again when the RPC is retried.
5098 * ESTALE: A forced dismount is in progress and will cause the
5099 * RPC to fail later.
5100 */
5101 *tl++ = 0;
5102 *tl++ = 0;
5103 *tl++ = 0;
5104 *tl = 0;
5105 }
5106 nd->nd_flag |= ND_HASSEQUENCE;
5107 }
5108
5109 /*
5110 * If fnd_init is true, ignore the badslots.
5111 * If fnd_init is false, return NFSERR_SEQMISORDERED if all slots are bad.
5112 */
5113 int
nfsv4_sequencelookup(struct nfsmount * nmp,struct nfsclsession * sep,int * slotposp,int * maxslotp,uint32_t * slotseqp,uint8_t * sessionid,bool fnd_init)5114 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
5115 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid,
5116 bool fnd_init)
5117 {
5118 int i, maxslot, slotpos;
5119 uint64_t bitval;
5120 bool fnd_ok;
5121
5122 /* Find an unused slot. */
5123 slotpos = -1;
5124 maxslot = -1;
5125 mtx_lock(&sep->nfsess_mtx);
5126 do {
5127 if (nmp != NULL && sep->nfsess_defunct != 0) {
5128 /* Just return the bad session. */
5129 bcopy(sep->nfsess_sessionid, sessionid,
5130 NFSX_V4SESSIONID);
5131 mtx_unlock(&sep->nfsess_mtx);
5132 return (NFSERR_BADSESSION);
5133 }
5134 fnd_ok = fnd_init;
5135 bitval = 1;
5136 for (i = 0; i < sep->nfsess_foreslots; i++) {
5137 if ((bitval & sep->nfsess_badslots) == 0 || fnd_init) {
5138 fnd_ok = true;
5139 if ((bitval & sep->nfsess_slots) == 0) {
5140 slotpos = i;
5141 sep->nfsess_slots |= bitval;
5142 sep->nfsess_slotseq[i]++;
5143 *slotseqp = sep->nfsess_slotseq[i];
5144 break;
5145 }
5146 }
5147 bitval <<= 1;
5148 }
5149 if (slotpos == -1) {
5150 /*
5151 * If a forced dismount is in progress, just return.
5152 * This RPC attempt will fail when it calls
5153 * newnfs_request().
5154 */
5155 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
5156 mtx_unlock(&sep->nfsess_mtx);
5157 return (ESTALE);
5158 }
5159 /* Wake up once/sec, to check for a forced dismount. */
5160 if (fnd_ok)
5161 mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
5162 PZERO, "nfsclseq", hz);
5163 }
5164 } while (slotpos == -1 && fnd_ok);
5165 /*
5166 * If all slots are bad, just return slot 0 and NFSERR_SEQMISORDERED.
5167 * The caller will do a DestroySession, so that the session's use
5168 * will get a NFSERR_BADSESSION reply from the server.
5169 */
5170 if (!fnd_ok)
5171 slotpos = 0;
5172
5173 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
5174 bitval = 1;
5175 for (i = 0; i < 64; i++) {
5176 if ((bitval & sep->nfsess_slots) != 0)
5177 maxslot = i;
5178 bitval <<= 1;
5179 }
5180 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
5181 mtx_unlock(&sep->nfsess_mtx);
5182 *slotposp = slotpos;
5183 *maxslotp = maxslot;
5184
5185 if (!fnd_ok)
5186 return (NFSERR_SEQMISORDERED);
5187 return (0);
5188 }
5189
5190 /*
5191 * Free a session slot.
5192 */
5193 void
nfsv4_freeslot(struct nfsclsession * sep,int slot,bool resetseq)5194 nfsv4_freeslot(struct nfsclsession *sep, int slot, bool resetseq)
5195 {
5196 uint64_t bitval;
5197
5198 bitval = 1;
5199 if (slot > 0)
5200 bitval <<= slot;
5201 mtx_lock(&sep->nfsess_mtx);
5202 if (resetseq)
5203 sep->nfsess_slotseq[slot]--;
5204 else if (slot > sep->nfsess_foreslots)
5205 sep->nfsess_slotseq[slot] = 0;
5206 if ((bitval & sep->nfsess_slots) == 0)
5207 printf("freeing free slot!!\n");
5208 sep->nfsess_slots &= ~bitval;
5209 wakeup(&sep->nfsess_slots);
5210 mtx_unlock(&sep->nfsess_mtx);
5211 }
5212
5213 /*
5214 * Search for a matching pnfsd DS, based on the nmp arg.
5215 * Return one if found, NULL otherwise.
5216 */
5217 struct nfsdevice *
nfsv4_findmirror(struct nfsmount * nmp)5218 nfsv4_findmirror(struct nfsmount *nmp)
5219 {
5220 struct nfsdevice *ds;
5221
5222 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
5223 /*
5224 * Search the DS server list for a match with nmp.
5225 */
5226 if (nfsrv_devidcnt == 0)
5227 return (NULL);
5228 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
5229 if (ds->nfsdev_nmp == nmp) {
5230 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
5231 break;
5232 }
5233 }
5234 return (ds);
5235 }
5236
5237 /*
5238 * Fill in the fields of "struct nfsrv_descript".
5239 */
5240 void
nfsm_set(struct nfsrv_descript * nd,u_int offs)5241 nfsm_set(struct nfsrv_descript *nd, u_int offs)
5242 {
5243 struct mbuf *m;
5244 int rlen;
5245
5246 m = nd->nd_mb;
5247 if ((m->m_flags & M_EXTPG) != 0) {
5248 nd->nd_bextpg = 0;
5249 while (offs > 0) {
5250 if (nd->nd_bextpg == 0)
5251 rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
5252 else
5253 rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
5254 if (offs <= rlen)
5255 break;
5256 offs -= rlen;
5257 nd->nd_bextpg++;
5258 if (nd->nd_bextpg == m->m_epg_npgs) {
5259 printf("nfsm_set: build offs "
5260 "out of range\n");
5261 nd->nd_bextpg--;
5262 break;
5263 }
5264 }
5265 nd->nd_bpos = (char *)(void *)
5266 PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
5267 if (nd->nd_bextpg == 0)
5268 nd->nd_bpos += m->m_epg_1st_off;
5269 if (offs > 0) {
5270 nd->nd_bpos += offs;
5271 nd->nd_bextpgsiz = rlen - offs;
5272 } else if (nd->nd_bextpg == 0)
5273 nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
5274 else
5275 nd->nd_bextpgsiz = PAGE_SIZE;
5276 } else
5277 nd->nd_bpos = mtod(m, char *) + offs;
5278 }
5279
5280 /*
5281 * Grow a ext_pgs mbuf list. Either allocate another page or add
5282 * an mbuf to the list.
5283 */
5284 struct mbuf *
nfsm_add_ext_pgs(struct mbuf * m,int maxextsiz,int * bextpg)5285 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
5286 {
5287 struct mbuf *mp;
5288 vm_page_t pg;
5289
5290 if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
5291 mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
5292 *bextpg = 0;
5293 m->m_next = mp;
5294 } else {
5295 pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP |
5296 VM_ALLOC_WIRED);
5297 m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
5298 *bextpg = m->m_epg_npgs;
5299 m->m_epg_npgs++;
5300 m->m_epg_last_len = 0;
5301 mp = m;
5302 }
5303 return (mp);
5304 }
5305
5306 /*
5307 * Do the NFSv4.1 Destroy Session.
5308 */
5309 int
nfsrpc_destroysession(struct nfsmount * nmp,struct nfsclsession * tsep,struct ucred * cred,NFSPROC_T * p)5310 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclsession *tsep,
5311 struct ucred *cred, NFSPROC_T *p)
5312 {
5313 uint32_t *tl;
5314 struct nfsrv_descript nfsd;
5315 struct nfsrv_descript *nd = &nfsd;
5316 int error;
5317
5318 if (tsep == NULL)
5319 tsep = nfsmnt_mdssession(nmp);
5320 if (tsep == NULL)
5321 return (0);
5322 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0,
5323 0, NULL);
5324 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
5325 bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
5326 nd->nd_flag |= ND_USEGSSNAME;
5327 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5328 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5329 if (error != 0)
5330 return (error);
5331 error = nd->nd_repstat;
5332 m_freem(nd->nd_mrep);
5333 return (error);
5334 }
5335
5336 /*
5337 * Translate a vnode type into an NFSv4 type, including the named
5338 * attribute types.
5339 */
5340 static uint32_t
vtonfsv4_type(struct vattr * vap)5341 vtonfsv4_type(struct vattr *vap)
5342 {
5343 nfstype ntyp;
5344
5345 if (vap->va_type >= 9)
5346 ntyp = NFNON;
5347 else
5348 ntyp = nfsv34_type[vap->va_type];
5349 if ((vap->va_bsdflags & SFBSD_NAMEDATTR) != 0) {
5350 if (ntyp == NFDIR)
5351 ntyp = NFATTRDIR;
5352 else if (ntyp == NFREG)
5353 ntyp = NFNAMEDATTR;
5354 }
5355 return (txdr_unsigned((uint32_t)ntyp));
5356 }
5357
5358 /*
5359 * Translate an NFS type to a vnode type.
5360 */
5361 static __enum_uint8(vtype)
nfsv4tov_type(uint32_t ntyp,uint16_t * bsdflags)5362 nfsv4tov_type(uint32_t ntyp, uint16_t *bsdflags)
5363 {
5364 __enum_uint8(vtype) vtyp;
5365
5366 ntyp = fxdr_unsigned(uint32_t, ntyp) % (NFNAMEDATTR + 1);
5367 if (ntyp == NFATTRDIR) {
5368 vtyp = VDIR;
5369 *bsdflags |= SFBSD_NAMEDATTR;
5370 } else if (ntyp == NFNAMEDATTR) {
5371 vtyp = VREG;
5372 *bsdflags |= SFBSD_NAMEDATTR;
5373 } else {
5374 vtyp = nv34tov_type[ntyp];
5375 }
5376 return (vtyp);
5377 }
5378