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