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