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