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