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