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