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