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