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