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