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