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