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