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