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