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