1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36 #include <sys/cdefs.h> 37 /* 38 * These functions support the macros and help fiddle mbuf chains for 39 * the nfs op functions. They do things like create the rpc header and 40 * copy data between mbuf chains and uio lists. 41 */ 42 #include "opt_inet.h" 43 #include "opt_inet6.h" 44 45 #include <fs/nfs/nfsport.h> 46 #include <fs/nfsclient/nfsmount.h> 47 48 #include <sys/extattr.h> 49 50 #include <security/mac/mac_framework.h> 51 52 #include <vm/vm_param.h> 53 54 /* 55 * Data items converted to xdr at startup, since they are constant 56 * This is kinda hokey, but may save a little time doing byte swaps 57 */ 58 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1; 59 60 /* And other global data */ 61 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, 62 NFFIFO, NFNON }; 63 __enum_uint8(vtype) newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; 64 __enum_uint8(vtype) nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 65 struct timeval nfsboottime; /* Copy boottime once, so it never changes */ 66 int nfscl_ticks; 67 int nfsrv_useacl = 1; 68 struct nfsreqhead nfsd_reqq; 69 int nfsrv_lease = NFSRV_LEASE; 70 int ncl_mbuf_mlen = MLEN; 71 int nfsrv_doflexfile = 0; 72 NFSNAMEIDMUTEX; 73 NFSSOCKMUTEX; 74 extern int nfsrv_lughashsize; 75 extern struct mtx nfsrv_dslock_mtx; 76 extern volatile int nfsrv_devidcnt; 77 extern int nfscl_debuglevel; 78 extern struct nfsdevicehead nfsrv_devidhead; 79 extern struct nfsstatsv1 nfsstatsv1; 80 extern uint32_t nfs_srvmaxio; 81 82 NFSD_VNET_DEFINE(int, nfsd_enable_stringtouid) = 0; 83 NFSD_VNET_DEFINE(struct nfssockreq, nfsrv_nfsuserdsock); 84 NFSD_VNET_DEFINE(nfsuserd_state, nfsrv_nfsuserd) = NOTRUNNING; 85 NFSD_VNET_DEFINE(uid_t, nfsrv_defaultuid) = UID_NOBODY; 86 NFSD_VNET_DEFINE(gid_t, nfsrv_defaultgid) = GID_NOGROUP; 87 88 NFSD_VNET_DEFINE_STATIC(int, nfsrv_userdupcalls) = 0; 89 90 SYSCTL_DECL(_vfs_nfs); 91 92 NFSD_VNET_DEFINE_STATIC(int, nfs_enable_uidtostring) = 0; 93 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, 94 CTLFLAG_NFSD_VNET | CTLFLAG_RW, &NFSD_VNET_NAME(nfs_enable_uidtostring), 0, 95 "Make nfs always send numeric owner_names"); 96 97 int nfsrv_maxpnfsmirror = 1; 98 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD, 99 &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service"); 100 101 /* 102 * This array of structures indicates, for V4: 103 * retfh - which of 3 types of calling args are used 104 * 0 - doesn't change cfh or use a sfh 105 * 1 - replaces cfh with a new one (unless it returns an error status) 106 * 2 - uses cfh and sfh 107 * needscfh - if the op wants a cfh and premtime 108 * 0 - doesn't use a cfh 109 * 1 - uses a cfh, but doesn't want pre-op attributes 110 * 2 - uses a cfh and wants pre-op attributes 111 * savereply - indicates a non-idempotent Op 112 * 0 - not non-idempotent 113 * 1 - non-idempotent 114 * Ops that are ordered via seqid# are handled separately from these 115 * non-idempotent Ops. 116 * Define it here, since it is used by both the client and server. 117 */ 118 struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = { 119 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ 120 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ 121 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ 122 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */ 123 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */ 124 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */ 125 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */ 126 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */ 127 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */ 128 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */ 129 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */ 130 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */ 131 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */ 132 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */ 133 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */ 134 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */ 135 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */ 136 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */ 137 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */ 138 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */ 139 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */ 140 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */ 141 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */ 142 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */ 143 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */ 144 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */ 145 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */ 146 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */ 147 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */ 148 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */ 149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */ 150 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */ 151 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */ 152 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */ 153 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */ 154 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */ 155 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */ 156 { 0, 2, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Verify (AppWrite) */ 157 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */ 158 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */ 159 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */ 160 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */ 161 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */ 162 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */ 163 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */ 164 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */ 165 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */ 166 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */ 167 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */ 168 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */ 169 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */ 170 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */ 171 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */ 172 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */ 173 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */ 174 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */ 175 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */ 176 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */ 177 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */ 178 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Allocate */ 179 { 2, 1, 1, 0, LK_SHARED, 1, 0 }, /* Copy */ 180 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy Notify */ 181 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Deallocate */ 182 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* IO Advise */ 183 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Error */ 184 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Stats */ 185 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Cancel */ 186 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Status */ 187 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Read Plus */ 188 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Seek */ 189 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Write Same */ 190 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Clone */ 191 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getxattr */ 192 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Setxattr */ 193 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Listxattrs */ 194 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Removexattr */ 195 }; 196 197 static int ncl_mbuf_mhlen = MHLEN; 198 struct nfsrv_lughash { 199 struct mtx mtx; 200 struct nfsuserhashhead lughead; 201 }; 202 203 NFSD_VNET_DEFINE_STATIC(int, nfsrv_usercnt) = 0; 204 NFSD_VNET_DEFINE_STATIC(int, nfsrv_dnsnamelen) = 0; 205 NFSD_VNET_DEFINE_STATIC(int, nfsrv_usermax) = 999999999; 206 NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsuserhash) = NULL; 207 NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsusernamehash) = NULL; 208 NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsgrouphash) = NULL; 209 NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsgroupnamehash) = NULL; 210 NFSD_VNET_DEFINE_STATIC(u_char *, nfsrv_dnsname) = NULL; 211 212 /* 213 * This static array indicates whether or not the RPC generates a large 214 * reply. This is used by nfs_reply() to decide whether or not an mbuf 215 * cluster should be allocated. (If a cluster is required by an RPC 216 * marked 0 in this array, the code will still work, just not quite as 217 * efficiently.) 218 */ 219 static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 220 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 222 1, 0, 0, 1, 0, 0, 0, 0, 0 }; 223 224 /* local functions */ 225 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); 226 static void nfsv4_wanted(struct nfsv4lock *lp); 227 static uint32_t nfsv4_filesavail(struct statfs *, struct mount *); 228 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len); 229 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name); 230 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser); 231 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **, 232 int *, int *); 233 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *); 234 235 static struct { 236 int op; 237 int opcnt; 238 const u_char *tag; 239 int taglen; 240 } nfsv4_opmap[NFSV42_NPROCS] = { 241 { 0, 1, "Null", 4 }, 242 { NFSV4OP_GETATTR, 1, "Getattr", 7, }, 243 { NFSV4OP_SETATTR, 2, "Setattr", 7, }, 244 { NFSV4OP_LOOKUP, 3, "Lookup", 6, }, 245 { NFSV4OP_ACCESS, 2, "Access", 6, }, 246 { NFSV4OP_READLINK, 2, "Readlink", 8, }, 247 { NFSV4OP_READ, 1, "Read", 4, }, 248 { NFSV4OP_WRITE, 2, "Write", 5, }, 249 { NFSV4OP_OPEN, 5, "Open", 4, }, 250 { NFSV4OP_CREATE, 5, "Create", 6, }, 251 { NFSV4OP_CREATE, 1, "Create", 6, }, 252 { NFSV4OP_CREATE, 3, "Create", 6, }, 253 { NFSV4OP_REMOVE, 1, "Remove", 6, }, 254 { NFSV4OP_REMOVE, 1, "Remove", 6, }, 255 { NFSV4OP_SAVEFH, 5, "Rename", 6, }, 256 { NFSV4OP_SAVEFH, 4, "Link", 4, }, 257 { NFSV4OP_READDIR, 2, "Readdir", 7, }, 258 { NFSV4OP_READDIR, 2, "Readdir", 7, }, 259 { NFSV4OP_GETATTR, 1, "Getattr", 7, }, 260 { NFSV4OP_GETATTR, 1, "Getattr", 7, }, 261 { NFSV4OP_GETATTR, 1, "Getattr", 7, }, 262 { NFSV4OP_COMMIT, 2, "Commit", 6, }, 263 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, }, 264 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, }, 265 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, }, 266 { NFSV4OP_LOCK, 1, "Lock", 4, }, 267 { NFSV4OP_LOCKU, 1, "LockU", 5, }, 268 { NFSV4OP_OPEN, 2, "Open", 4, }, 269 { NFSV4OP_CLOSE, 1, "Close", 5, }, 270 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, }, 271 { NFSV4OP_LOCKT, 1, "LockT", 5, }, 272 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, }, 273 { NFSV4OP_RENEW, 1, "Renew", 5, }, 274 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, }, 275 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, }, 276 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, }, 277 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, }, 278 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, }, 279 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, }, 280 { NFSV4OP_GETATTR, 1, "Getacl", 6, }, 281 { NFSV4OP_SETATTR, 1, "Setacl", 6, }, 282 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, }, 283 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, }, 284 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, }, 285 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, }, 286 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, }, 287 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, }, 288 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, }, 289 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, }, 290 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, }, 291 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, }, 292 { NFSV4OP_WRITE, 1, "WriteDS", 7, }, 293 { NFSV4OP_READ, 1, "ReadDS", 6, }, 294 { NFSV4OP_COMMIT, 1, "CommitDS", 8, }, 295 { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, }, 296 { NFSV4OP_OPEN, 8, "CreateLayGet", 12, }, 297 { NFSV4OP_IOADVISE, 1, "Advise", 6, }, 298 { NFSV4OP_ALLOCATE, 2, "Allocate", 8, }, 299 { NFSV4OP_SAVEFH, 5, "Copy", 4, }, 300 { NFSV4OP_SEEK, 2, "Seek", 4, }, 301 { NFSV4OP_SEEK, 1, "SeekDS", 6, }, 302 { NFSV4OP_GETXATTR, 2, "Getxattr", 8, }, 303 { NFSV4OP_SETXATTR, 2, "Setxattr", 8, }, 304 { NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, }, 305 { NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, }, 306 { NFSV4OP_BINDCONNTOSESS, 1, "BindConSess", 11, }, 307 { NFSV4OP_LOOKUP, 5, "LookupOpen", 10, }, 308 { NFSV4OP_DEALLOCATE, 2, "Deallocate", 10, }, 309 { NFSV4OP_LAYOUTERROR, 1, "LayoutError", 11, }, 310 { NFSV4OP_VERIFY, 3, "AppendWrite", 11, }, 311 }; 312 313 /* 314 * NFS RPCS that have large request message size. 315 */ 316 static int nfs_bigrequest[NFSV42_NPROCS] = { 317 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 318 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 320 0, 1 321 }; 322 323 /* 324 * Start building a request. Mostly just put the first file handle in 325 * place. 326 */ 327 void 328 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp, 329 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep, 330 int vers, int minorvers, struct ucred *cred) 331 { 332 struct mbuf *mb; 333 u_int32_t *tl; 334 int opcnt; 335 nfsattrbit_t attrbits; 336 337 /* 338 * First, fill in some of the fields of nd. 339 */ 340 nd->nd_slotseq = NULL; 341 if (vers == NFS_VER4) { 342 nd->nd_flag = ND_NFSV4 | ND_NFSCL; 343 if (minorvers == NFSV41_MINORVERSION) 344 nd->nd_flag |= ND_NFSV41; 345 else if (minorvers == NFSV42_MINORVERSION) 346 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42); 347 } else if (vers == NFS_VER3) 348 nd->nd_flag = ND_NFSV3 | ND_NFSCL; 349 else { 350 if (NFSHASNFSV4(nmp)) { 351 nd->nd_flag = ND_NFSV4 | ND_NFSCL; 352 if (nmp->nm_minorvers == 1) 353 nd->nd_flag |= ND_NFSV41; 354 else if (nmp->nm_minorvers == 2) 355 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42); 356 } else if (NFSHASNFSV3(nmp)) 357 nd->nd_flag = ND_NFSV3 | ND_NFSCL; 358 else 359 nd->nd_flag = ND_NFSV2 | ND_NFSCL; 360 } 361 nd->nd_procnum = procnum; 362 nd->nd_repstat = 0; 363 nd->nd_maxextsiz = 0; 364 365 /* 366 * Get the first mbuf for the request. 367 */ 368 if (nfs_bigrequest[procnum]) 369 NFSMCLGET(mb, M_WAITOK); 370 else 371 NFSMGET(mb); 372 mb->m_len = 0; 373 nd->nd_mreq = nd->nd_mb = mb; 374 nd->nd_bpos = mtod(mb, char *); 375 376 /* For NFSPROC_NULL, there are no arguments. */ 377 if (procnum == NFSPROC_NULL) 378 goto out; 379 380 /* 381 * And fill the first file handle into the request. 382 */ 383 if (nd->nd_flag & ND_NFSV4) { 384 opcnt = nfsv4_opmap[procnum].opcnt + 385 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh; 386 if ((nd->nd_flag & ND_NFSV41) != 0) { 387 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq; 388 if (procnum == NFSPROC_RENEW) 389 /* 390 * For the special case of Renew, just do a 391 * Sequence Op. 392 */ 393 opcnt = 1; 394 else if (procnum == NFSPROC_WRITEDS || 395 procnum == NFSPROC_COMMITDS) 396 /* 397 * For the special case of a Writeor Commit to 398 * a DS, the opcnt == 3, for Sequence, PutFH, 399 * Write/Commit. 400 */ 401 opcnt = 3; 402 } 403 /* 404 * What should the tag really be? 405 */ 406 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag, 407 nfsv4_opmap[procnum].taglen); 408 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 409 if ((nd->nd_flag & ND_NFSV42) != 0) 410 *tl++ = txdr_unsigned(NFSV42_MINORVERSION); 411 else if ((nd->nd_flag & ND_NFSV41) != 0) 412 *tl++ = txdr_unsigned(NFSV41_MINORVERSION); 413 else 414 *tl++ = txdr_unsigned(NFSV4_MINORVERSION); 415 if (opcntpp != NULL) 416 *opcntpp = tl; 417 *tl = txdr_unsigned(opcnt); 418 if ((nd->nd_flag & ND_NFSV41) != 0 && 419 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) { 420 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess > 421 0) 422 nd->nd_flag |= ND_LOOPBADSESS; 423 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 424 *tl = txdr_unsigned(NFSV4OP_SEQUENCE); 425 if (sep == NULL) { 426 sep = nfsmnt_mdssession(nmp); 427 /* 428 * For MDS mount sessions, check for bad 429 * slots. If the caller does not want this 430 * check to be done, the "cred" argument can 431 * be passed in as NULL. 432 */ 433 nfsv4_setsequence(nmp, nd, sep, 434 nfs_bigreply[procnum], cred); 435 } else 436 nfsv4_setsequence(nmp, nd, sep, 437 nfs_bigreply[procnum], NULL); 438 } 439 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) { 440 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 441 *tl = txdr_unsigned(NFSV4OP_PUTFH); 442 (void)nfsm_fhtom(nmp, nd, nfhp, fhlen, 0); 443 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh 444 == 2 && procnum != NFSPROC_WRITEDS && 445 procnum != NFSPROC_COMMITDS) { 446 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 447 *tl = txdr_unsigned(NFSV4OP_GETATTR); 448 /* 449 * For Lookup Ops, we want all the directory 450 * attributes, so we can load the name cache. 451 */ 452 if (procnum == NFSPROC_LOOKUP || 453 procnum == NFSPROC_LOOKUPP || 454 procnum == NFSPROC_LOOKUPOPEN) 455 NFSGETATTR_ATTRBIT(&attrbits); 456 else { 457 NFSWCCATTR_ATTRBIT(&attrbits); 458 /* For AppendWrite, get the size. */ 459 if (procnum == NFSPROC_APPENDWRITE) 460 NFSSETBIT_ATTRBIT(&attrbits, 461 NFSATTRBIT_SIZE); 462 nd->nd_flag |= ND_V4WCCATTR; 463 } 464 (void) nfsrv_putattrbit(nd, &attrbits); 465 } 466 } 467 if (procnum != NFSPROC_RENEW || 468 (nd->nd_flag & ND_NFSV41) == 0) { 469 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 470 *tl = txdr_unsigned(nfsv4_opmap[procnum].op); 471 } 472 } else { 473 (void)nfsm_fhtom(NULL, nd, nfhp, fhlen, 0); 474 } 475 out: 476 if (procnum < NFSV42_NPROCS) 477 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]); 478 } 479 480 /* 481 * Put a state Id in the mbuf list. 482 */ 483 void 484 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag) 485 { 486 nfsv4stateid_t *st; 487 488 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID); 489 if (flag == NFSSTATEID_PUTALLZERO) { 490 st->seqid = 0; 491 st->other[0] = 0; 492 st->other[1] = 0; 493 st->other[2] = 0; 494 } else if (flag == NFSSTATEID_PUTALLONE) { 495 st->seqid = 0xffffffff; 496 st->other[0] = 0xffffffff; 497 st->other[1] = 0xffffffff; 498 st->other[2] = 0xffffffff; 499 } else if (flag == NFSSTATEID_PUTSEQIDZERO) { 500 st->seqid = 0; 501 st->other[0] = stateidp->other[0]; 502 st->other[1] = stateidp->other[1]; 503 st->other[2] = stateidp->other[2]; 504 } else { 505 st->seqid = stateidp->seqid; 506 st->other[0] = stateidp->other[0]; 507 st->other[1] = stateidp->other[1]; 508 st->other[2] = stateidp->other[2]; 509 } 510 } 511 512 /* 513 * Fill in the setable attributes. The full argument indicates whether 514 * to fill in them all or just mode and time. 515 */ 516 void 517 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap, 518 struct vnode *vp, int flags, u_int32_t rdev) 519 { 520 u_int32_t *tl; 521 struct nfsv2_sattr *sp; 522 nfsattrbit_t attrbits; 523 struct nfsnode *np; 524 525 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { 526 case ND_NFSV2: 527 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 528 if (vap->va_mode == (mode_t)VNOVAL) 529 sp->sa_mode = newnfs_xdrneg1; 530 else 531 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 532 if (vap->va_uid == (uid_t)VNOVAL) 533 sp->sa_uid = newnfs_xdrneg1; 534 else 535 sp->sa_uid = txdr_unsigned(vap->va_uid); 536 if (vap->va_gid == (gid_t)VNOVAL) 537 sp->sa_gid = newnfs_xdrneg1; 538 else 539 sp->sa_gid = txdr_unsigned(vap->va_gid); 540 if (flags & NFSSATTR_SIZE0) 541 sp->sa_size = 0; 542 else if (flags & NFSSATTR_SIZENEG1) 543 sp->sa_size = newnfs_xdrneg1; 544 else if (flags & NFSSATTR_SIZERDEV) 545 sp->sa_size = txdr_unsigned(rdev); 546 else 547 sp->sa_size = txdr_unsigned(vap->va_size); 548 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); 549 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); 550 break; 551 case ND_NFSV3: 552 if (vap->va_mode != (mode_t)VNOVAL) { 553 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 554 *tl++ = newnfs_true; 555 *tl = txdr_unsigned(vap->va_mode); 556 } else { 557 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 558 *tl = newnfs_false; 559 } 560 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) { 561 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 562 *tl++ = newnfs_true; 563 *tl = txdr_unsigned(vap->va_uid); 564 } else { 565 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 566 *tl = newnfs_false; 567 } 568 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) { 569 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 570 *tl++ = newnfs_true; 571 *tl = txdr_unsigned(vap->va_gid); 572 } else { 573 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 574 *tl = newnfs_false; 575 } 576 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) { 577 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 578 *tl++ = newnfs_true; 579 txdr_hyper(vap->va_size, tl); 580 } else { 581 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 582 *tl = newnfs_false; 583 } 584 if (vap->va_atime.tv_sec != VNOVAL) { 585 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 586 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 587 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 588 txdr_nfsv3time(&vap->va_atime, tl); 589 } else { 590 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 591 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 592 } 593 } else { 594 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 595 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 596 } 597 if (vap->va_mtime.tv_sec != VNOVAL) { 598 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 599 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 600 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 601 txdr_nfsv3time(&vap->va_mtime, tl); 602 } else { 603 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 604 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 605 } 606 } else { 607 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 608 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 609 } 610 break; 611 case ND_NFSV4: 612 NFSZERO_ATTRBIT(&attrbits); 613 np = NULL; 614 if (strcmp(vp->v_mount->mnt_vfc->vfc_name, "nfs") == 0) 615 np = VTONFS(vp); 616 if (vap->va_mode != (mode_t)VNOVAL) { 617 if ((flags & NFSSATTR_NEWFILE) != 0 && np != NULL && 618 NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, 619 NFSATTRBIT_MODEUMASK)) 620 NFSSETBIT_ATTRBIT(&attrbits, 621 NFSATTRBIT_MODEUMASK); 622 else 623 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE); 624 } 625 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) 626 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 627 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) 628 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP); 629 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) 630 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE); 631 if (vap->va_atime.tv_sec != VNOVAL) 632 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); 633 if (vap->va_mtime.tv_sec != VNOVAL) 634 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET); 635 /* 636 * We can only test for support of TimeCreate if 637 * the "vp" argument is for an NFS vnode. 638 */ 639 if (vap->va_birthtime.tv_sec != VNOVAL && np != NULL && 640 NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, 641 NFSATTRBIT_TIMECREATE)) 642 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE); 643 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0, 644 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL); 645 break; 646 } 647 } 648 649 /* 650 * copies mbuf chain to the uio scatter/gather list 651 */ 652 int 653 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz) 654 { 655 char *mbufcp, *uiocp; 656 int xfer, left, len; 657 struct mbuf *mp; 658 long uiosiz, rem; 659 int error = 0; 660 661 mp = nd->nd_md; 662 mbufcp = nd->nd_dpos; 663 len = mtod(mp, caddr_t) + mp->m_len - mbufcp; 664 rem = NFSM_RNDUP(siz) - siz; 665 while (siz > 0) { 666 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) { 667 error = EBADRPC; 668 goto out; 669 } 670 left = uiop->uio_iov->iov_len; 671 uiocp = uiop->uio_iov->iov_base; 672 if (left > siz) 673 left = siz; 674 uiosiz = left; 675 while (left > 0) { 676 while (len == 0) { 677 mp = mp->m_next; 678 if (mp == NULL) { 679 error = EBADRPC; 680 goto out; 681 } 682 mbufcp = mtod(mp, caddr_t); 683 len = mp->m_len; 684 KASSERT(len >= 0, 685 ("len %d, corrupted mbuf?", len)); 686 } 687 xfer = (left > len) ? len : left; 688 if (uiop->uio_segflg == UIO_SYSSPACE) 689 NFSBCOPY(mbufcp, uiocp, xfer); 690 else { 691 error = copyout(mbufcp, uiocp, xfer); 692 if (error != 0) 693 goto out; 694 } 695 left -= xfer; 696 len -= xfer; 697 mbufcp += xfer; 698 uiocp += xfer; 699 uiop->uio_offset += xfer; 700 uiop->uio_resid -= xfer; 701 } 702 if (uiop->uio_iov->iov_len <= siz) { 703 uiop->uio_iovcnt--; 704 uiop->uio_iov++; 705 } else { 706 uiop->uio_iov->iov_base = (void *) 707 ((char *)uiop->uio_iov->iov_base + uiosiz); 708 uiop->uio_iov->iov_len -= uiosiz; 709 } 710 siz -= uiosiz; 711 } 712 nd->nd_dpos = mbufcp; 713 nd->nd_md = mp; 714 if (rem > 0) { 715 if (len < rem) 716 error = nfsm_advance(nd, rem, len); 717 else 718 nd->nd_dpos += rem; 719 } 720 721 out: 722 NFSEXITCODE2(error, nd); 723 return (error); 724 } 725 726 /* 727 * Help break down an mbuf chain by setting the first siz bytes contiguous 728 * pointed to by returned val. 729 * This is used by the macro NFSM_DISSECT for tough 730 * cases. 731 */ 732 void * 733 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how) 734 { 735 struct mbuf *mp2; 736 int siz2, xfer; 737 caddr_t p; 738 int left; 739 caddr_t retp; 740 741 retp = NULL; 742 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos; 743 while (left == 0) { 744 nd->nd_md = nd->nd_md->m_next; 745 if (nd->nd_md == NULL) 746 return (retp); 747 left = nd->nd_md->m_len; 748 nd->nd_dpos = mtod(nd->nd_md, caddr_t); 749 } 750 if (left >= siz) { 751 retp = nd->nd_dpos; 752 nd->nd_dpos += siz; 753 } else if (nd->nd_md->m_next == NULL) { 754 return (retp); 755 } else if (siz > ncl_mbuf_mhlen) { 756 panic("nfs S too big"); 757 } else { 758 MGET(mp2, how, MT_DATA); 759 if (mp2 == NULL) 760 return (NULL); 761 mp2->m_next = nd->nd_md->m_next; 762 nd->nd_md->m_next = mp2; 763 nd->nd_md->m_len -= left; 764 nd->nd_md = mp2; 765 retp = p = mtod(mp2, caddr_t); 766 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */ 767 siz2 = siz - left; 768 p += left; 769 mp2 = mp2->m_next; 770 /* Loop around copying up the siz2 bytes */ 771 while (siz2 > 0) { 772 if (mp2 == NULL) 773 return (NULL); 774 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 775 if (xfer > 0) { 776 NFSBCOPY(mtod(mp2, caddr_t), p, xfer); 777 mp2->m_data += xfer; 778 mp2->m_len -= xfer; 779 p += xfer; 780 siz2 -= xfer; 781 } 782 if (siz2 > 0) 783 mp2 = mp2->m_next; 784 } 785 nd->nd_md->m_len = siz; 786 nd->nd_md = mp2; 787 nd->nd_dpos = mtod(mp2, caddr_t); 788 } 789 return (retp); 790 } 791 792 /* 793 * Advance the position in the mbuf chain. 794 * If offs == 0, this is a no-op, but it is simpler to just return from 795 * here than check for offs > 0 for all calls to nfsm_advance. 796 * If left == -1, it should be calculated here. 797 */ 798 int 799 nfsm_advance(struct nfsrv_descript *nd, int offs, int left) 800 { 801 int error = 0; 802 803 if (offs == 0) 804 goto out; 805 /* 806 * A negative offs might indicate a corrupted mbuf chain and, 807 * as such, a printf is logged. 808 */ 809 if (offs < 0) { 810 printf("nfsrv_advance: negative offs\n"); 811 error = EBADRPC; 812 goto out; 813 } 814 815 /* 816 * If left == -1, calculate it here. 817 */ 818 if (left == -1) 819 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - 820 nd->nd_dpos; 821 822 /* 823 * Loop around, advancing over the mbuf data. 824 */ 825 while (offs > left) { 826 offs -= left; 827 nd->nd_md = nd->nd_md->m_next; 828 if (nd->nd_md == NULL) { 829 error = EBADRPC; 830 goto out; 831 } 832 left = nd->nd_md->m_len; 833 nd->nd_dpos = mtod(nd->nd_md, caddr_t); 834 } 835 nd->nd_dpos += offs; 836 837 out: 838 NFSEXITCODE(error); 839 return (error); 840 } 841 842 /* 843 * Copy a string into mbuf(s). 844 * Return the number of bytes output, including XDR overheads. 845 */ 846 int 847 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz) 848 { 849 struct mbuf *m2; 850 int xfer, left; 851 struct mbuf *m1; 852 int rem, bytesize; 853 u_int32_t *tl; 854 char *cp2; 855 856 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 857 *tl = txdr_unsigned(siz); 858 rem = NFSM_RNDUP(siz) - siz; 859 bytesize = NFSX_UNSIGNED + siz + rem; 860 m2 = nd->nd_mb; 861 cp2 = nd->nd_bpos; 862 if ((nd->nd_flag & ND_EXTPG) != 0) 863 left = nd->nd_bextpgsiz; 864 else 865 left = M_TRAILINGSPACE(m2); 866 867 KASSERT(((m2->m_flags & (M_EXT | M_EXTPG)) == 868 (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) != 0) || 869 ((m2->m_flags & (M_EXT | M_EXTPG)) != 870 (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) == 0), 871 ("nfsm_strtom: ext_pgs and non-ext_pgs mbufs mixed")); 872 /* 873 * Loop around copying the string to mbuf(s). 874 */ 875 while (siz > 0) { 876 if (left == 0) { 877 if ((nd->nd_flag & ND_EXTPG) != 0) { 878 m2 = nfsm_add_ext_pgs(m2, 879 nd->nd_maxextsiz, &nd->nd_bextpg); 880 cp2 = (char *)(void *)PHYS_TO_DMAP( 881 m2->m_epg_pa[nd->nd_bextpg]); 882 nd->nd_bextpgsiz = left = PAGE_SIZE; 883 } else { 884 if (siz > ncl_mbuf_mlen) 885 NFSMCLGET(m1, M_WAITOK); 886 else 887 NFSMGET(m1); 888 m1->m_len = 0; 889 cp2 = mtod(m1, char *); 890 left = M_TRAILINGSPACE(m1); 891 m2->m_next = m1; 892 m2 = m1; 893 } 894 } 895 if (left >= siz) 896 xfer = siz; 897 else 898 xfer = left; 899 NFSBCOPY(cp, cp2, xfer); 900 cp += xfer; 901 cp2 += xfer; 902 m2->m_len += xfer; 903 siz -= xfer; 904 left -= xfer; 905 if ((nd->nd_flag & ND_EXTPG) != 0) { 906 nd->nd_bextpgsiz -= xfer; 907 m2->m_epg_last_len += xfer; 908 } 909 if (siz == 0 && rem) { 910 if (left < rem) 911 panic("nfsm_strtom"); 912 NFSBZERO(cp2, rem); 913 m2->m_len += rem; 914 cp2 += rem; 915 if ((nd->nd_flag & ND_EXTPG) != 0) { 916 nd->nd_bextpgsiz -= rem; 917 m2->m_epg_last_len += rem; 918 } 919 } 920 } 921 nd->nd_mb = m2; 922 if ((nd->nd_flag & ND_EXTPG) != 0) 923 nd->nd_bpos = cp2; 924 else 925 nd->nd_bpos = mtod(m2, char *) + m2->m_len; 926 return (bytesize); 927 } 928 929 /* 930 * Called once to initialize data structures... 931 */ 932 void 933 newnfs_init(void) 934 { 935 static int nfs_inited = 0; 936 937 if (nfs_inited) 938 return; 939 nfs_inited = 1; 940 941 newnfs_true = txdr_unsigned(TRUE); 942 newnfs_false = txdr_unsigned(FALSE); 943 newnfs_xdrneg1 = txdr_unsigned(-1); 944 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 945 if (nfscl_ticks < 1) 946 nfscl_ticks = 1; 947 NFSSETBOOTTIME(nfsboottime); 948 949 /* 950 * Initialize reply list and start timer 951 */ 952 TAILQ_INIT(&nfsd_reqq); 953 } 954 955 /* 956 * Put a file handle in an mbuf list. 957 * If the size argument == 0, just use the default size. 958 * set_true == 1 if there should be an newnfs_true prepended on the file handle. 959 * Return the number of bytes output, including XDR overhead. 960 */ 961 int 962 nfsm_fhtom(struct nfsmount *nmp, struct nfsrv_descript *nd, u_int8_t *fhp, 963 int size, int set_true) 964 { 965 u_int32_t *tl; 966 u_int8_t *cp; 967 int fullsiz, bytesize = 0; 968 969 KASSERT(nmp == NULL || nmp->nm_fhsize > 0, 970 ("nfsm_fhtom: 0 length fh")); 971 if (size == 0) 972 size = NFSX_MYFH; 973 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { 974 case ND_NFSV2: 975 if (size > NFSX_V2FH) 976 panic("fh size > NFSX_V2FH for NFSv2"); 977 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH); 978 NFSBCOPY(fhp, cp, size); 979 if (size < NFSX_V2FH) 980 NFSBZERO(cp + size, NFSX_V2FH - size); 981 bytesize = NFSX_V2FH; 982 break; 983 case ND_NFSV3: 984 case ND_NFSV4: 985 if (size == NFSX_FHMAX + 1 && nmp != NULL && 986 (nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) { 987 fhp = nmp->nm_fh; 988 size = nmp->nm_fhsize; 989 } 990 fullsiz = NFSM_RNDUP(size); 991 if (set_true) { 992 bytesize = 2 * NFSX_UNSIGNED + fullsiz; 993 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 994 *tl = newnfs_true; 995 } else { 996 bytesize = NFSX_UNSIGNED + fullsiz; 997 } 998 (void) nfsm_strtom(nd, fhp, size); 999 break; 1000 } 1001 return (bytesize); 1002 } 1003 1004 /* 1005 * This function compares two net addresses by family and returns TRUE 1006 * if they are the same host. 1007 * If there is any doubt, return FALSE. 1008 * The AF_INET family is handled as a special case so that address mbufs 1009 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1010 */ 1011 int 1012 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam) 1013 { 1014 #ifdef INET 1015 struct sockaddr_in *inetaddr; 1016 #endif 1017 1018 switch (family) { 1019 #ifdef INET 1020 case AF_INET: 1021 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *); 1022 if (inetaddr->sin_family == AF_INET && 1023 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr) 1024 return (1); 1025 break; 1026 #endif 1027 #ifdef INET6 1028 case AF_INET6: 1029 { 1030 struct sockaddr_in6 *inetaddr6; 1031 1032 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *); 1033 /* XXX - should test sin6_scope_id ? */ 1034 if (inetaddr6->sin6_family == AF_INET6 && 1035 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr, 1036 &haddr->had_inet6)) 1037 return (1); 1038 } 1039 break; 1040 #endif 1041 } 1042 return (0); 1043 } 1044 1045 /* 1046 * Similar to the above, but takes to NFSSOCKADDR_T args. 1047 */ 1048 int 1049 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2) 1050 { 1051 struct sockaddr_in *addr1, *addr2; 1052 struct sockaddr *inaddr; 1053 1054 inaddr = NFSSOCKADDR(nam1, struct sockaddr *); 1055 switch (inaddr->sa_family) { 1056 case AF_INET: 1057 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *); 1058 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *); 1059 if (addr2->sin_family == AF_INET && 1060 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) 1061 return (1); 1062 break; 1063 #ifdef INET6 1064 case AF_INET6: 1065 { 1066 struct sockaddr_in6 *inet6addr1, *inet6addr2; 1067 1068 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *); 1069 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *); 1070 /* XXX - should test sin6_scope_id ? */ 1071 if (inet6addr2->sin6_family == AF_INET6 && 1072 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 1073 &inet6addr2->sin6_addr)) 1074 return (1); 1075 } 1076 break; 1077 #endif 1078 } 1079 return (0); 1080 } 1081 1082 /* 1083 * Dissect a file handle on the client. 1084 */ 1085 int 1086 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp) 1087 { 1088 u_int32_t *tl; 1089 struct nfsfh *nfhp; 1090 int error, len; 1091 1092 *nfhpp = NULL; 1093 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1094 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1095 if ((len = fxdr_unsigned(int, *tl)) <= 0 || 1096 len > NFSX_FHMAX) { 1097 error = EBADRPC; 1098 goto nfsmout; 1099 } 1100 } else 1101 len = NFSX_V2FH; 1102 nfhp = malloc(sizeof (struct nfsfh) + len, 1103 M_NFSFH, M_WAITOK); 1104 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len); 1105 if (error) { 1106 free(nfhp, M_NFSFH); 1107 goto nfsmout; 1108 } 1109 nfhp->nfh_len = len; 1110 *nfhpp = nfhp; 1111 nfsmout: 1112 NFSEXITCODE2(error, nd); 1113 return (error); 1114 } 1115 1116 /* 1117 * Break down the nfsv4 acl. 1118 * If the aclp == NULL or won't fit in an acl, just discard the acl info. 1119 */ 1120 int 1121 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, bool server, 1122 int *aclerrp, int *aclsizep, __unused NFSPROC_T *p) 1123 { 1124 u_int32_t *tl; 1125 int i, aclsize; 1126 int acecnt, error = 0, aceerr = 0, acesize; 1127 1128 *aclerrp = 0; 1129 if (aclp) 1130 aclp->acl_cnt = 0; 1131 /* 1132 * Parse out the ace entries and expect them to conform to 1133 * what can be supported by R/W/X bits. 1134 */ 1135 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1136 aclsize = NFSX_UNSIGNED; 1137 acecnt = fxdr_unsigned(int, *tl); 1138 /* 1139 * The RFCs do not define a fixed limit to the number of ACEs in 1140 * an ACL, but 10240 should be more than sufficient. 1141 */ 1142 if (acecnt < 0 || acecnt > 10240) { 1143 error = NFSERR_BADXDR; 1144 goto nfsmout; 1145 } 1146 if (acecnt > ACL_MAX_ENTRIES) 1147 aceerr = NFSERR_ATTRNOTSUPP; 1148 if (nfsrv_useacl == 0) 1149 aceerr = NFSERR_ATTRNOTSUPP; 1150 for (i = 0; i < acecnt; i++) { 1151 if (aclp && !aceerr) 1152 error = nfsrv_dissectace(nd, &aclp->acl_entry[i], 1153 server, &aceerr, &acesize, p); 1154 else 1155 error = nfsrv_skipace(nd, &acesize); 1156 if (error) 1157 goto nfsmout; 1158 aclsize += acesize; 1159 } 1160 if (aclp && !aceerr) 1161 aclp->acl_cnt = acecnt; 1162 if (aceerr) 1163 *aclerrp = aceerr; 1164 if (aclsizep) 1165 *aclsizep = aclsize; 1166 nfsmout: 1167 NFSEXITCODE2(error, nd); 1168 return (error); 1169 } 1170 1171 /* 1172 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it. 1173 */ 1174 static int 1175 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep) 1176 { 1177 u_int32_t *tl; 1178 int error, len = 0; 1179 1180 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1181 len = fxdr_unsigned(int, *(tl + 3)); 1182 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 1183 nfsmout: 1184 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); 1185 NFSEXITCODE2(error, nd); 1186 return (error); 1187 } 1188 1189 /* 1190 * Get attribute bits from an mbuf list. 1191 * Returns EBADRPC for a parsing error, 0 otherwise. 1192 * If the clearinvalid flag is set, clear the bits not supported. 1193 */ 1194 int 1195 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp, 1196 int *retnotsupp) 1197 { 1198 u_int32_t *tl; 1199 int cnt, i, outcnt; 1200 int error = 0; 1201 1202 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1203 cnt = fxdr_unsigned(int, *tl); 1204 if (cnt < 0) { 1205 error = NFSERR_BADXDR; 1206 goto nfsmout; 1207 } 1208 if (cnt > NFSATTRBIT_MAXWORDS) 1209 outcnt = NFSATTRBIT_MAXWORDS; 1210 else 1211 outcnt = cnt; 1212 NFSZERO_ATTRBIT(attrbitp); 1213 if (outcnt > 0) { 1214 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED); 1215 for (i = 0; i < outcnt; i++) 1216 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++); 1217 } 1218 for (i = 0; i < (cnt - outcnt); i++) { 1219 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1220 if (retnotsupp != NULL && *tl != 0) 1221 *retnotsupp = NFSERR_ATTRNOTSUPP; 1222 } 1223 if (cntp) 1224 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED); 1225 nfsmout: 1226 NFSEXITCODE2(error, nd); 1227 return (error); 1228 } 1229 1230 /* 1231 * Get operation bits from an mbuf list. 1232 * Returns EBADRPC for a parsing error, 0 otherwise. 1233 */ 1234 int 1235 nfsrv_getopbits(struct nfsrv_descript *nd, nfsopbit_t *opbitp, int *cntp) 1236 { 1237 uint32_t *tl; 1238 int cnt, i, outcnt; 1239 int error = 0; 1240 1241 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 1242 cnt = fxdr_unsigned(int, *tl); 1243 if (cnt < 0) { 1244 error = NFSERR_BADXDR; 1245 goto nfsmout; 1246 } 1247 if (cnt > NFSOPBIT_MAXWORDS) 1248 outcnt = NFSOPBIT_MAXWORDS; 1249 else 1250 outcnt = cnt; 1251 NFSZERO_OPBIT(opbitp); 1252 if (outcnt > 0) { 1253 NFSM_DISSECT(tl, uint32_t *, outcnt * NFSX_UNSIGNED); 1254 for (i = 0; i < outcnt; i++) 1255 opbitp->bits[i] = fxdr_unsigned(uint32_t, *tl++); 1256 } 1257 for (i = 0; i < (cnt - outcnt); i++) { 1258 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 1259 if (*tl != 0) { 1260 error = NFSERR_BADXDR; 1261 goto nfsmout; 1262 } 1263 } 1264 if (cntp != NULL) 1265 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED); 1266 nfsmout: 1267 NFSEXITCODE2(error, nd); 1268 return (error); 1269 } 1270 1271 /* 1272 * Get the attributes for V4. 1273 * If the compare flag is true, test for any attribute changes, 1274 * otherwise return the attribute values. 1275 * These attributes cover fields in "struct vattr", "struct statfs", 1276 * "struct nfsfsinfo", the file handle and the lease duration. 1277 * The value of retcmpp is set to 1 if all attributes are the same, 1278 * and 0 otherwise. 1279 * Returns EBADRPC if it can't be parsed, 0 otherwise. 1280 */ 1281 int 1282 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, 1283 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize, 1284 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp, 1285 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp, 1286 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred) 1287 { 1288 u_int32_t *tl; 1289 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0; 1290 int error, tfhsize, aceerr, attrsize, cnt, retnotsup; 1291 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1]; 1292 nfsattrbit_t attrbits, retattrbits, checkattrbits; 1293 struct nfsfh *tnfhp; 1294 struct nfsreferral *refp; 1295 u_quad_t tquad; 1296 nfsquad_t tnfsquad; 1297 struct timespec temptime; 1298 uid_t uid; 1299 gid_t gid; 1300 u_int32_t freenum = 0, tuint; 1301 u_int64_t uquad = 0, thyp, thyp2; 1302 #ifdef QUOTA 1303 struct dqblk dqb; 1304 uid_t savuid; 1305 #endif 1306 1307 CTASSERT(sizeof(ino_t) == sizeof(uint64_t)); 1308 NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread)); 1309 if (compare) { 1310 retnotsup = 0; 1311 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); 1312 } else { 1313 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1314 } 1315 if (error) 1316 goto nfsmout; 1317 1318 if (compare) { 1319 *retcmpp = retnotsup; 1320 } else { 1321 /* 1322 * Just set default values to some of the important ones. 1323 */ 1324 if (nap != NULL) { 1325 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 case NFSATTRBIT_MODEUMASK: 3119 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3120 /* 3121 * Since FreeBSD applies the umask above the VFS/VOP, 3122 * there is no umask to handle here. If FreeBSD 3123 * moves handling of umask to below the VFS/VOP, 3124 * this could change. 3125 */ 3126 *tl++ = vtonfsv34_mode(vap->va_mode); 3127 *tl = 0; 3128 retnum += 2 * NFSX_UNSIGNED; 3129 break; 3130 default: 3131 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 3132 } 3133 } 3134 } 3135 if (naclp != NULL) 3136 acl_free(naclp); 3137 free(fs, M_STATFS); 3138 *retnump = txdr_unsigned(retnum); 3139 return (retnum + prefixnum); 3140 } 3141 3142 /* 3143 * Calculate the files available attribute value. 3144 */ 3145 static uint32_t 3146 nfsv4_filesavail(struct statfs *fs, struct mount *mp) 3147 { 3148 uint32_t freenum; 3149 #ifdef QUOTA 3150 struct dqblk dqb; 3151 uid_t savuid; 3152 NFSPROC_T *p; 3153 #endif 3154 3155 /* 3156 * Check quota and use min(quota, f_ffree). 3157 */ 3158 freenum = fs->f_ffree; 3159 #ifdef QUOTA 3160 /* 3161 * This is old OpenBSD code that does not build 3162 * for FreeBSD. I do not know if doing this is 3163 * useful, so I will just leave the code here. 3164 */ 3165 p = curthread(); 3166 /* 3167 * ufs_quotactl() insists that the uid argument 3168 * equal p_ruid for non-root quota access, so 3169 * we'll just make sure that's the case. 3170 */ 3171 savuid = p->p_cred->p_ruid; 3172 p->p_cred->p_ruid = cred->cr_uid; 3173 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 3174 cred->cr_uid, &dqb)) 3175 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 3176 freenum); 3177 p->p_cred->p_ruid = savuid; 3178 #endif /* QUOTA */ 3179 return (freenum); 3180 } 3181 3182 /* 3183 * Put the attribute bits onto an mbuf list. 3184 * Return the number of bytes of output generated. 3185 */ 3186 int 3187 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 3188 { 3189 u_int32_t *tl; 3190 int cnt, i, bytesize; 3191 3192 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 3193 if (attrbitp->bits[cnt - 1]) 3194 break; 3195 bytesize = (cnt + 1) * NFSX_UNSIGNED; 3196 NFSM_BUILD(tl, u_int32_t *, bytesize); 3197 *tl++ = txdr_unsigned(cnt); 3198 for (i = 0; i < cnt; i++) 3199 *tl++ = txdr_unsigned(attrbitp->bits[i]); 3200 return (bytesize); 3201 } 3202 3203 /* 3204 * Put the operation bits onto an mbuf list. 3205 * Return the number of bytes of output generated. 3206 */ 3207 int 3208 nfsrv_putopbit(struct nfsrv_descript *nd, nfsopbit_t *opbitp) 3209 { 3210 uint32_t *tl; 3211 int cnt, i, bytesize; 3212 3213 for (cnt = NFSOPBIT_MAXWORDS; cnt > 0; cnt--) 3214 if (opbitp->bits[cnt - 1]) 3215 break; 3216 bytesize = (cnt + 1) * NFSX_UNSIGNED; 3217 NFSM_BUILD(tl, uint32_t *, bytesize); 3218 *tl++ = txdr_unsigned(cnt); 3219 for (i = 0; i < cnt; i++) 3220 *tl++ = txdr_unsigned(opbitp->bits[i]); 3221 return (bytesize); 3222 } 3223 3224 /* 3225 * Convert a uid to a string. 3226 * If the lookup fails, just output the digits. 3227 * uid - the user id 3228 * cpp - points to a buffer of size NFSV4_SMALLSTR 3229 * (malloc a larger one, as required) 3230 * retlenp - pointer to length to be returned 3231 */ 3232 void 3233 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp) 3234 { 3235 int i; 3236 struct nfsusrgrp *usrp; 3237 u_char *cp = *cpp; 3238 uid_t tmp; 3239 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 3240 struct nfsrv_lughash *hp; 3241 3242 NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread)); 3243 cnt = 0; 3244 tryagain: 3245 if (NFSD_VNET(nfsrv_dnsnamelen) > 0 && 3246 !NFSD_VNET(nfs_enable_uidtostring)) { 3247 /* 3248 * Always map nfsrv_defaultuid to "nobody". 3249 */ 3250 if (uid == NFSD_VNET(nfsrv_defaultuid)) { 3251 i = NFSD_VNET(nfsrv_dnsnamelen) + 7; 3252 if (i > len) { 3253 if (len > NFSV4_SMALLSTR) 3254 free(cp, M_NFSSTRING); 3255 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3256 *cpp = cp; 3257 len = i; 3258 goto tryagain; 3259 } 3260 *retlenp = i; 3261 NFSBCOPY("nobody@", cp, 7); 3262 cp += 7; 3263 NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp, 3264 NFSD_VNET(nfsrv_dnsnamelen)); 3265 NFSD_CURVNET_RESTORE(); 3266 return; 3267 } 3268 hasampersand = 0; 3269 hp = NFSUSERHASH(uid); 3270 mtx_lock(&hp->mtx); 3271 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 3272 if (usrp->lug_uid == uid) { 3273 if (usrp->lug_expiry < NFSD_MONOSEC) 3274 break; 3275 /* 3276 * If the name doesn't already have an '@' 3277 * in it, append @domainname to it. 3278 */ 3279 for (i = 0; i < usrp->lug_namelen; i++) { 3280 if (usrp->lug_name[i] == '@') { 3281 hasampersand = 1; 3282 break; 3283 } 3284 } 3285 if (hasampersand) 3286 i = usrp->lug_namelen; 3287 else 3288 i = usrp->lug_namelen + 3289 NFSD_VNET(nfsrv_dnsnamelen) + 1; 3290 if (i > len) { 3291 mtx_unlock(&hp->mtx); 3292 if (len > NFSV4_SMALLSTR) 3293 free(cp, M_NFSSTRING); 3294 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3295 *cpp = cp; 3296 len = i; 3297 goto tryagain; 3298 } 3299 *retlenp = i; 3300 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 3301 if (!hasampersand) { 3302 cp += usrp->lug_namelen; 3303 *cp++ = '@'; 3304 NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp, 3305 NFSD_VNET(nfsrv_dnsnamelen)); 3306 } 3307 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3308 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 3309 lug_numhash); 3310 mtx_unlock(&hp->mtx); 3311 NFSD_CURVNET_RESTORE(); 3312 return; 3313 } 3314 } 3315 mtx_unlock(&hp->mtx); 3316 cnt++; 3317 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL); 3318 if (ret == 0 && cnt < 2) 3319 goto tryagain; 3320 } 3321 3322 /* 3323 * No match, just return a string of digits. 3324 */ 3325 tmp = uid; 3326 i = 0; 3327 while (tmp || i == 0) { 3328 tmp /= 10; 3329 i++; 3330 } 3331 len = (i > len) ? len : i; 3332 *retlenp = len; 3333 cp += (len - 1); 3334 tmp = uid; 3335 for (i = 0; i < len; i++) { 3336 *cp-- = '0' + (tmp % 10); 3337 tmp /= 10; 3338 } 3339 NFSD_CURVNET_RESTORE(); 3340 return; 3341 } 3342 3343 /* 3344 * Get a credential for the uid with the server's group list. 3345 * If none is found, just return the credential passed in after 3346 * logging a warning message. 3347 */ 3348 struct ucred * 3349 nfsrv_getgrpscred(struct ucred *oldcred) 3350 { 3351 struct nfsusrgrp *usrp; 3352 struct ucred *newcred; 3353 int cnt, ret; 3354 uid_t uid; 3355 struct nfsrv_lughash *hp; 3356 3357 cnt = 0; 3358 uid = oldcred->cr_uid; 3359 tryagain: 3360 if (NFSD_VNET(nfsrv_dnsnamelen) > 0) { 3361 hp = NFSUSERHASH(uid); 3362 mtx_lock(&hp->mtx); 3363 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 3364 if (usrp->lug_uid == uid) { 3365 if (usrp->lug_expiry < NFSD_MONOSEC) 3366 break; 3367 if (usrp->lug_cred != NULL) { 3368 newcred = crhold(usrp->lug_cred); 3369 crfree(oldcred); 3370 } else 3371 newcred = oldcred; 3372 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3373 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 3374 lug_numhash); 3375 mtx_unlock(&hp->mtx); 3376 return (newcred); 3377 } 3378 } 3379 mtx_unlock(&hp->mtx); 3380 cnt++; 3381 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL); 3382 if (ret == 0 && cnt < 2) 3383 goto tryagain; 3384 } 3385 return (oldcred); 3386 } 3387 3388 /* 3389 * Convert a string to a uid. 3390 * If no conversion is possible return NFSERR_BADOWNER, otherwise 3391 * return 0. 3392 * If this is called from a client side mount using AUTH_SYS and the 3393 * string is made up entirely of digits, just convert the string to 3394 * a number. 3395 */ 3396 int 3397 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp) 3398 { 3399 int i; 3400 char *cp, *endstr, *str0; 3401 struct nfsusrgrp *usrp; 3402 int cnt, ret; 3403 int error = 0; 3404 uid_t tuid; 3405 struct nfsrv_lughash *hp, *hp2; 3406 3407 NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread)); 3408 if (len == 0) { 3409 error = NFSERR_BADOWNER; 3410 goto out; 3411 } 3412 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 3413 str0 = str; 3414 tuid = (uid_t)strtoul(str0, &endstr, 10); 3415 if ((endstr - str0) == len) { 3416 /* A numeric string. */ 3417 if ((nd->nd_flag & ND_KERBV) == 0 && 3418 ((nd->nd_flag & ND_NFSCL) != 0 || 3419 NFSD_VNET(nfsd_enable_stringtouid) != 0)) 3420 *uidp = tuid; 3421 else 3422 error = NFSERR_BADOWNER; 3423 goto out; 3424 } 3425 /* 3426 * Look for an '@'. 3427 */ 3428 cp = strchr(str0, '@'); 3429 if (cp != NULL) 3430 i = (int)(cp++ - str0); 3431 else 3432 i = len; 3433 3434 cnt = 0; 3435 tryagain: 3436 if (NFSD_VNET(nfsrv_dnsnamelen) > 0) { 3437 /* 3438 * If an '@' is found and the domain name matches, search for 3439 * the name with dns stripped off. 3440 * Mixed case alpahbetics will match for the domain name, but 3441 * all upper case will not. 3442 */ 3443 if (cnt == 0 && i < len && i > 0 && 3444 (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) && 3445 !nfsrv_cmpmixedcase(cp, 3446 NFSD_VNET(nfsrv_dnsname), NFSD_VNET(nfsrv_dnsnamelen))) { 3447 len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1); 3448 *(cp - 1) = '\0'; 3449 } 3450 3451 /* 3452 * Check for the special case of "nobody". 3453 */ 3454 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 3455 *uidp = NFSD_VNET(nfsrv_defaultuid); 3456 error = 0; 3457 goto out; 3458 } 3459 3460 hp = NFSUSERNAMEHASH(str, len); 3461 mtx_lock(&hp->mtx); 3462 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 3463 if (usrp->lug_namelen == len && 3464 !NFSBCMP(usrp->lug_name, str, len)) { 3465 if (usrp->lug_expiry < NFSD_MONOSEC) 3466 break; 3467 hp2 = NFSUSERHASH(usrp->lug_uid); 3468 mtx_lock(&hp2->mtx); 3469 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 3470 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 3471 lug_numhash); 3472 *uidp = usrp->lug_uid; 3473 mtx_unlock(&hp2->mtx); 3474 mtx_unlock(&hp->mtx); 3475 error = 0; 3476 goto out; 3477 } 3478 } 3479 mtx_unlock(&hp->mtx); 3480 cnt++; 3481 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 3482 str); 3483 if (ret == 0 && cnt < 2) 3484 goto tryagain; 3485 } 3486 error = NFSERR_BADOWNER; 3487 3488 out: 3489 NFSD_CURVNET_RESTORE(); 3490 NFSEXITCODE(error); 3491 return (error); 3492 } 3493 3494 /* 3495 * Convert a gid to a string. 3496 * gid - the group id 3497 * cpp - points to a buffer of size NFSV4_SMALLSTR 3498 * (malloc a larger one, as required) 3499 * retlenp - pointer to length to be returned 3500 */ 3501 void 3502 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp) 3503 { 3504 int i; 3505 struct nfsusrgrp *usrp; 3506 u_char *cp = *cpp; 3507 gid_t tmp; 3508 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 3509 struct nfsrv_lughash *hp; 3510 3511 NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread)); 3512 cnt = 0; 3513 tryagain: 3514 if (NFSD_VNET(nfsrv_dnsnamelen) > 0 && 3515 !NFSD_VNET(nfs_enable_uidtostring)) { 3516 /* 3517 * Always map nfsrv_defaultgid to "nogroup". 3518 */ 3519 if (gid == NFSD_VNET(nfsrv_defaultgid)) { 3520 i = NFSD_VNET(nfsrv_dnsnamelen) + 8; 3521 if (i > len) { 3522 if (len > NFSV4_SMALLSTR) 3523 free(cp, M_NFSSTRING); 3524 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3525 *cpp = cp; 3526 len = i; 3527 goto tryagain; 3528 } 3529 *retlenp = i; 3530 NFSBCOPY("nogroup@", cp, 8); 3531 cp += 8; 3532 NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp, 3533 NFSD_VNET(nfsrv_dnsnamelen)); 3534 NFSD_CURVNET_RESTORE(); 3535 return; 3536 } 3537 hasampersand = 0; 3538 hp = NFSGROUPHASH(gid); 3539 mtx_lock(&hp->mtx); 3540 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 3541 if (usrp->lug_gid == gid) { 3542 if (usrp->lug_expiry < NFSD_MONOSEC) 3543 break; 3544 /* 3545 * If the name doesn't already have an '@' 3546 * in it, append @domainname to it. 3547 */ 3548 for (i = 0; i < usrp->lug_namelen; i++) { 3549 if (usrp->lug_name[i] == '@') { 3550 hasampersand = 1; 3551 break; 3552 } 3553 } 3554 if (hasampersand) 3555 i = usrp->lug_namelen; 3556 else 3557 i = usrp->lug_namelen + 3558 NFSD_VNET(nfsrv_dnsnamelen) + 1; 3559 if (i > len) { 3560 mtx_unlock(&hp->mtx); 3561 if (len > NFSV4_SMALLSTR) 3562 free(cp, M_NFSSTRING); 3563 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3564 *cpp = cp; 3565 len = i; 3566 goto tryagain; 3567 } 3568 *retlenp = i; 3569 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 3570 if (!hasampersand) { 3571 cp += usrp->lug_namelen; 3572 *cp++ = '@'; 3573 NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp, 3574 NFSD_VNET(nfsrv_dnsnamelen)); 3575 } 3576 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3577 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 3578 lug_numhash); 3579 mtx_unlock(&hp->mtx); 3580 NFSD_CURVNET_RESTORE(); 3581 return; 3582 } 3583 } 3584 mtx_unlock(&hp->mtx); 3585 cnt++; 3586 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL); 3587 if (ret == 0 && cnt < 2) 3588 goto tryagain; 3589 } 3590 3591 /* 3592 * No match, just return a string of digits. 3593 */ 3594 tmp = gid; 3595 i = 0; 3596 while (tmp || i == 0) { 3597 tmp /= 10; 3598 i++; 3599 } 3600 len = (i > len) ? len : i; 3601 *retlenp = len; 3602 cp += (len - 1); 3603 tmp = gid; 3604 for (i = 0; i < len; i++) { 3605 *cp-- = '0' + (tmp % 10); 3606 tmp /= 10; 3607 } 3608 NFSD_CURVNET_RESTORE(); 3609 return; 3610 } 3611 3612 /* 3613 * Convert a string to a gid. 3614 * If no conversion is possible return NFSERR_BADOWNER, otherwise 3615 * return 0. 3616 * If this is called from a client side mount using AUTH_SYS and the 3617 * string is made up entirely of digits, just convert the string to 3618 * a number. 3619 */ 3620 int 3621 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp) 3622 { 3623 int i; 3624 char *cp, *endstr, *str0; 3625 struct nfsusrgrp *usrp; 3626 int cnt, ret; 3627 int error = 0; 3628 gid_t tgid; 3629 struct nfsrv_lughash *hp, *hp2; 3630 3631 NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread)); 3632 if (len == 0) { 3633 error = NFSERR_BADOWNER; 3634 goto out; 3635 } 3636 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 3637 str0 = str; 3638 tgid = (gid_t)strtoul(str0, &endstr, 10); 3639 if ((endstr - str0) == len) { 3640 /* A numeric string. */ 3641 if ((nd->nd_flag & ND_KERBV) == 0 && 3642 ((nd->nd_flag & ND_NFSCL) != 0 || 3643 NFSD_VNET(nfsd_enable_stringtouid) != 0)) 3644 *gidp = tgid; 3645 else 3646 error = NFSERR_BADOWNER; 3647 goto out; 3648 } 3649 /* 3650 * Look for an '@'. 3651 */ 3652 cp = strchr(str0, '@'); 3653 if (cp != NULL) 3654 i = (int)(cp++ - str0); 3655 else 3656 i = len; 3657 3658 cnt = 0; 3659 tryagain: 3660 if (NFSD_VNET(nfsrv_dnsnamelen) > 0) { 3661 /* 3662 * If an '@' is found and the dns name matches, search for the 3663 * name with the dns stripped off. 3664 */ 3665 if (cnt == 0 && i < len && i > 0 && 3666 (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) && 3667 !nfsrv_cmpmixedcase(cp, 3668 NFSD_VNET(nfsrv_dnsname), NFSD_VNET(nfsrv_dnsnamelen))) { 3669 len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1); 3670 *(cp - 1) = '\0'; 3671 } 3672 3673 /* 3674 * Check for the special case of "nogroup". 3675 */ 3676 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 3677 *gidp = NFSD_VNET(nfsrv_defaultgid); 3678 error = 0; 3679 goto out; 3680 } 3681 3682 hp = NFSGROUPNAMEHASH(str, len); 3683 mtx_lock(&hp->mtx); 3684 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 3685 if (usrp->lug_namelen == len && 3686 !NFSBCMP(usrp->lug_name, str, len)) { 3687 if (usrp->lug_expiry < NFSD_MONOSEC) 3688 break; 3689 hp2 = NFSGROUPHASH(usrp->lug_gid); 3690 mtx_lock(&hp2->mtx); 3691 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 3692 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 3693 lug_numhash); 3694 *gidp = usrp->lug_gid; 3695 mtx_unlock(&hp2->mtx); 3696 mtx_unlock(&hp->mtx); 3697 error = 0; 3698 goto out; 3699 } 3700 } 3701 mtx_unlock(&hp->mtx); 3702 cnt++; 3703 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 3704 str); 3705 if (ret == 0 && cnt < 2) 3706 goto tryagain; 3707 } 3708 error = NFSERR_BADOWNER; 3709 3710 out: 3711 NFSD_CURVNET_RESTORE(); 3712 NFSEXITCODE(error); 3713 return (error); 3714 } 3715 3716 /* 3717 * Cmp len chars, allowing mixed case in the first argument to match lower 3718 * case in the second, but not if the first argument is all upper case. 3719 * Return 0 for a match, 1 otherwise. 3720 */ 3721 static int 3722 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 3723 { 3724 int i; 3725 u_char tmp; 3726 int fndlower = 0; 3727 3728 for (i = 0; i < len; i++) { 3729 if (*cp >= 'A' && *cp <= 'Z') { 3730 tmp = *cp++ + ('a' - 'A'); 3731 } else { 3732 tmp = *cp++; 3733 if (tmp >= 'a' && tmp <= 'z') 3734 fndlower = 1; 3735 } 3736 if (tmp != *cp2++) 3737 return (1); 3738 } 3739 if (fndlower) 3740 return (0); 3741 else 3742 return (1); 3743 } 3744 3745 /* 3746 * Set the port for the nfsuserd. 3747 */ 3748 int 3749 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p) 3750 { 3751 struct nfssockreq *rp; 3752 #ifdef INET 3753 struct sockaddr_in *ad; 3754 #endif 3755 #ifdef INET6 3756 struct sockaddr_in6 *ad6; 3757 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT; 3758 #endif 3759 int error; 3760 3761 NFSLOCKNAMEID(); 3762 if (NFSD_VNET(nfsrv_nfsuserd) != NOTRUNNING) { 3763 NFSUNLOCKNAMEID(); 3764 error = EPERM; 3765 goto out; 3766 } 3767 NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP; 3768 /* 3769 * Set up the socket record and connect. 3770 * Set nr_client NULL before unlocking, just to ensure that no other 3771 * process/thread/core will use a bogus old value. This could only 3772 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is 3773 * broken. 3774 */ 3775 rp = &NFSD_VNET(nfsrv_nfsuserdsock); 3776 rp->nr_client = NULL; 3777 NFSUNLOCKNAMEID(); 3778 rp->nr_sotype = SOCK_DGRAM; 3779 rp->nr_soproto = IPPROTO_UDP; 3780 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 3781 rp->nr_cred = NULL; 3782 rp->nr_prog = RPCPROG_NFSUSERD; 3783 error = 0; 3784 switch (nargs->nuserd_family) { 3785 #ifdef INET 3786 case AF_INET: 3787 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME, 3788 M_WAITOK | M_ZERO); 3789 ad = (struct sockaddr_in *)rp->nr_nam; 3790 ad->sin_len = sizeof(struct sockaddr_in); 3791 ad->sin_family = AF_INET; 3792 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 3793 ad->sin_port = nargs->nuserd_port; 3794 break; 3795 #endif 3796 #ifdef INET6 3797 case AF_INET6: 3798 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 3799 M_WAITOK | M_ZERO); 3800 ad6 = (struct sockaddr_in6 *)rp->nr_nam; 3801 ad6->sin6_len = sizeof(struct sockaddr_in6); 3802 ad6->sin6_family = AF_INET6; 3803 ad6->sin6_addr = in6loopback; 3804 ad6->sin6_port = nargs->nuserd_port; 3805 break; 3806 #endif 3807 default: 3808 error = ENXIO; 3809 } 3810 rp->nr_vers = RPCNFSUSERD_VERS; 3811 if (error == 0) 3812 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false, 3813 &rp->nr_client); 3814 if (error == 0) { 3815 NFSLOCKNAMEID(); 3816 NFSD_VNET(nfsrv_nfsuserd) = RUNNING; 3817 NFSUNLOCKNAMEID(); 3818 } else { 3819 free(rp->nr_nam, M_SONAME); 3820 NFSLOCKNAMEID(); 3821 NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING; 3822 NFSUNLOCKNAMEID(); 3823 } 3824 out: 3825 NFSEXITCODE(error); 3826 return (error); 3827 } 3828 3829 /* 3830 * Delete the nfsuserd port. 3831 */ 3832 void 3833 nfsrv_nfsuserddelport(void) 3834 { 3835 3836 NFSLOCKNAMEID(); 3837 if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) { 3838 NFSUNLOCKNAMEID(); 3839 return; 3840 } 3841 NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP; 3842 /* Wait for all upcalls to complete. */ 3843 while (NFSD_VNET(nfsrv_userdupcalls) > 0) 3844 msleep(&NFSD_VNET(nfsrv_userdupcalls), NFSNAMEIDMUTEXPTR, PVFS, 3845 "nfsupcalls", 0); 3846 NFSUNLOCKNAMEID(); 3847 newnfs_disconnect(NULL, &NFSD_VNET(nfsrv_nfsuserdsock)); 3848 free(NFSD_VNET(nfsrv_nfsuserdsock).nr_nam, M_SONAME); 3849 NFSLOCKNAMEID(); 3850 NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING; 3851 NFSUNLOCKNAMEID(); 3852 } 3853 3854 /* 3855 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 3856 * name<-->id cache. 3857 * Returns 0 upon success, non-zero otherwise. 3858 */ 3859 static int 3860 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name) 3861 { 3862 u_int32_t *tl; 3863 struct nfsrv_descript *nd; 3864 int len; 3865 struct nfsrv_descript nfsd; 3866 struct ucred *cred; 3867 int error; 3868 3869 NFSLOCKNAMEID(); 3870 if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) { 3871 NFSUNLOCKNAMEID(); 3872 error = EPERM; 3873 goto out; 3874 } 3875 /* 3876 * Maintain a count of upcalls in progress, so that nfsrv_X() 3877 * can wait until no upcalls are in progress. 3878 */ 3879 NFSD_VNET(nfsrv_userdupcalls)++; 3880 NFSUNLOCKNAMEID(); 3881 KASSERT(NFSD_VNET(nfsrv_userdupcalls) > 0, 3882 ("nfsrv_getuser: non-positive upcalls")); 3883 nd = &nfsd; 3884 cred = newnfs_getcred(); 3885 nd->nd_flag = ND_GSSINITREPLY; 3886 nfsrvd_rephead(nd); 3887 3888 nd->nd_procnum = procnum; 3889 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3890 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3891 if (procnum == RPCNFSUSERD_GETUID) 3892 *tl = txdr_unsigned(uid); 3893 else 3894 *tl = txdr_unsigned(gid); 3895 } else { 3896 len = strlen(name); 3897 (void) nfsm_strtom(nd, name, len); 3898 } 3899 error = newnfs_request(nd, NULL, NULL, &NFSD_VNET(nfsrv_nfsuserdsock), 3900 NULL, NULL, cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, 3901 NULL, NULL); 3902 NFSLOCKNAMEID(); 3903 if (--NFSD_VNET(nfsrv_userdupcalls) == 0 && 3904 NFSD_VNET(nfsrv_nfsuserd) == STARTSTOP) 3905 wakeup(&NFSD_VNET(nfsrv_userdupcalls)); 3906 NFSUNLOCKNAMEID(); 3907 NFSFREECRED(cred); 3908 if (!error) { 3909 m_freem(nd->nd_mrep); 3910 error = nd->nd_repstat; 3911 } 3912 out: 3913 NFSEXITCODE(error); 3914 return (error); 3915 } 3916 3917 /* 3918 * This function is called from the nfssvc(2) system call, to update the 3919 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3920 */ 3921 int 3922 nfssvc_idname(struct nfsd_idargs *nidp) 3923 { 3924 struct nfsusrgrp *nusrp, *usrp, *newusrp; 3925 struct nfsrv_lughash *hp_name, *hp_idnum, *thp; 3926 int i, group_locked, groupname_locked, user_locked, username_locked; 3927 int error = 0; 3928 u_char *cp; 3929 gid_t *grps; 3930 struct ucred *cr; 3931 static int onethread = 0; 3932 static time_t lasttime = 0; 3933 3934 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) { 3935 error = EINVAL; 3936 goto out; 3937 } 3938 if (nidp->nid_flag & NFSID_INITIALIZE) { 3939 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); 3940 error = copyin(nidp->nid_name, cp, nidp->nid_namelen); 3941 if (error != 0) { 3942 free(cp, M_NFSSTRING); 3943 goto out; 3944 } 3945 if (atomic_cmpset_acq_int(&NFSD_VNET(nfsrv_dnsnamelen), 0, 0) == 3946 0) { 3947 /* 3948 * Free up all the old stuff and reinitialize hash 3949 * lists. All mutexes for both lists must be locked, 3950 * with the user/group name ones before the uid/gid 3951 * ones, to avoid a LOR. 3952 */ 3953 for (i = 0; i < nfsrv_lughashsize; i++) 3954 mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx); 3955 for (i = 0; i < nfsrv_lughashsize; i++) 3956 mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx); 3957 for (i = 0; i < nfsrv_lughashsize; i++) 3958 TAILQ_FOREACH_SAFE(usrp, 3959 &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash, nusrp) 3960 nfsrv_removeuser(usrp, 1); 3961 for (i = 0; i < nfsrv_lughashsize; i++) 3962 mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx); 3963 for (i = 0; i < nfsrv_lughashsize; i++) 3964 mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx); 3965 for (i = 0; i < nfsrv_lughashsize; i++) 3966 mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx); 3967 for (i = 0; i < nfsrv_lughashsize; i++) 3968 mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx); 3969 for (i = 0; i < nfsrv_lughashsize; i++) 3970 TAILQ_FOREACH_SAFE(usrp, 3971 &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash, 3972 nusrp) 3973 nfsrv_removeuser(usrp, 0); 3974 for (i = 0; i < nfsrv_lughashsize; i++) 3975 mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx); 3976 for (i = 0; i < nfsrv_lughashsize; i++) 3977 mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx); 3978 free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING); 3979 NFSD_VNET(nfsrv_dnsname) = NULL; 3980 } 3981 if (NFSD_VNET(nfsuserhash) == NULL) { 3982 /* Allocate the hash tables. */ 3983 NFSD_VNET(nfsuserhash) = malloc(sizeof(struct nfsrv_lughash) * 3984 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3985 M_ZERO); 3986 for (i = 0; i < nfsrv_lughashsize; i++) 3987 mtx_init(&NFSD_VNET(nfsuserhash)[i].mtx, "nfsuidhash", 3988 NULL, MTX_DEF | MTX_DUPOK); 3989 NFSD_VNET(nfsusernamehash) = malloc(sizeof(struct nfsrv_lughash) * 3990 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3991 M_ZERO); 3992 for (i = 0; i < nfsrv_lughashsize; i++) 3993 mtx_init(&NFSD_VNET(nfsusernamehash)[i].mtx, 3994 "nfsusrhash", NULL, MTX_DEF | 3995 MTX_DUPOK); 3996 NFSD_VNET(nfsgrouphash) = malloc(sizeof(struct nfsrv_lughash) * 3997 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3998 M_ZERO); 3999 for (i = 0; i < nfsrv_lughashsize; i++) 4000 mtx_init(&NFSD_VNET(nfsgrouphash)[i].mtx, "nfsgidhash", 4001 NULL, MTX_DEF | MTX_DUPOK); 4002 NFSD_VNET(nfsgroupnamehash) = malloc(sizeof(struct nfsrv_lughash) * 4003 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 4004 M_ZERO); 4005 for (i = 0; i < nfsrv_lughashsize; i++) 4006 mtx_init(&NFSD_VNET(nfsgroupnamehash)[i].mtx, 4007 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK); 4008 } 4009 /* (Re)initialize the list heads. */ 4010 for (i = 0; i < nfsrv_lughashsize; i++) 4011 TAILQ_INIT(&NFSD_VNET(nfsuserhash)[i].lughead); 4012 for (i = 0; i < nfsrv_lughashsize; i++) 4013 TAILQ_INIT(&NFSD_VNET(nfsusernamehash)[i].lughead); 4014 for (i = 0; i < nfsrv_lughashsize; i++) 4015 TAILQ_INIT(&NFSD_VNET(nfsgrouphash)[i].lughead); 4016 for (i = 0; i < nfsrv_lughashsize; i++) 4017 TAILQ_INIT(&NFSD_VNET(nfsgroupnamehash)[i].lughead); 4018 4019 /* 4020 * Put name in "DNS" string. 4021 */ 4022 NFSD_VNET(nfsrv_dnsname) = cp; 4023 NFSD_VNET(nfsrv_defaultuid) = nidp->nid_uid; 4024 NFSD_VNET(nfsrv_defaultgid) = nidp->nid_gid; 4025 NFSD_VNET(nfsrv_usercnt) = 0; 4026 NFSD_VNET(nfsrv_usermax) = nidp->nid_usermax; 4027 atomic_store_rel_int(&NFSD_VNET(nfsrv_dnsnamelen), 4028 nidp->nid_namelen); 4029 goto out; 4030 } 4031 4032 /* 4033 * malloc the new one now, so any potential sleep occurs before 4034 * manipulation of the lists. 4035 */ 4036 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, 4037 M_NFSUSERGROUP, M_WAITOK | M_ZERO); 4038 error = copyin(nidp->nid_name, newusrp->lug_name, 4039 nidp->nid_namelen); 4040 if (error == 0 && nidp->nid_ngroup > 0 && 4041 (nidp->nid_flag & NFSID_ADDUID) != 0) { 4042 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP, 4043 M_WAITOK); 4044 error = copyin(nidp->nid_grps, grps, 4045 sizeof(gid_t) * nidp->nid_ngroup); 4046 if (error == 0) { 4047 /* 4048 * Create a credential just like svc_getcred(), 4049 * but using the group list provided. 4050 */ 4051 cr = crget(); 4052 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; 4053 crsetgroups(cr, nidp->nid_ngroup, grps); 4054 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; 4055 cr->cr_prison = curthread->td_ucred->cr_prison; 4056 prison_hold(cr->cr_prison); 4057 #ifdef MAC 4058 mac_cred_associate_nfsd(cr); 4059 #endif 4060 newusrp->lug_cred = cr; 4061 } 4062 free(grps, M_TEMP); 4063 } 4064 if (error) { 4065 free(newusrp, M_NFSUSERGROUP); 4066 goto out; 4067 } 4068 newusrp->lug_namelen = nidp->nid_namelen; 4069 4070 /* 4071 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed 4072 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group. 4073 * The flags user_locked, username_locked, group_locked and 4074 * groupname_locked are set to indicate all of those hash lists are 4075 * locked. hp_name != NULL and hp_idnum != NULL indicates that 4076 * the respective one mutex is locked. 4077 */ 4078 user_locked = username_locked = group_locked = groupname_locked = 0; 4079 hp_name = hp_idnum = NULL; 4080 4081 /* 4082 * Delete old entries, as required. 4083 */ 4084 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 4085 /* Must lock all username hash lists first, to avoid a LOR. */ 4086 for (i = 0; i < nfsrv_lughashsize; i++) 4087 mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx); 4088 username_locked = 1; 4089 hp_idnum = NFSUSERHASH(nidp->nid_uid); 4090 mtx_lock(&hp_idnum->mtx); 4091 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 4092 nusrp) { 4093 if (usrp->lug_uid == nidp->nid_uid) 4094 nfsrv_removeuser(usrp, 1); 4095 } 4096 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 4097 hp_name = NFSUSERNAMEHASH(newusrp->lug_name, 4098 newusrp->lug_namelen); 4099 mtx_lock(&hp_name->mtx); 4100 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 4101 nusrp) { 4102 if (usrp->lug_namelen == newusrp->lug_namelen && 4103 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 4104 usrp->lug_namelen)) { 4105 thp = NFSUSERHASH(usrp->lug_uid); 4106 mtx_lock(&thp->mtx); 4107 nfsrv_removeuser(usrp, 1); 4108 mtx_unlock(&thp->mtx); 4109 } 4110 } 4111 hp_idnum = NFSUSERHASH(nidp->nid_uid); 4112 mtx_lock(&hp_idnum->mtx); 4113 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 4114 /* Must lock all groupname hash lists first, to avoid a LOR. */ 4115 for (i = 0; i < nfsrv_lughashsize; i++) 4116 mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx); 4117 groupname_locked = 1; 4118 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 4119 mtx_lock(&hp_idnum->mtx); 4120 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 4121 nusrp) { 4122 if (usrp->lug_gid == nidp->nid_gid) 4123 nfsrv_removeuser(usrp, 0); 4124 } 4125 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 4126 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name, 4127 newusrp->lug_namelen); 4128 mtx_lock(&hp_name->mtx); 4129 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 4130 nusrp) { 4131 if (usrp->lug_namelen == newusrp->lug_namelen && 4132 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 4133 usrp->lug_namelen)) { 4134 thp = NFSGROUPHASH(usrp->lug_gid); 4135 mtx_lock(&thp->mtx); 4136 nfsrv_removeuser(usrp, 0); 4137 mtx_unlock(&thp->mtx); 4138 } 4139 } 4140 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 4141 mtx_lock(&hp_idnum->mtx); 4142 } 4143 4144 /* 4145 * Now, we can add the new one. 4146 */ 4147 if (nidp->nid_usertimeout) 4148 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 4149 else 4150 newusrp->lug_expiry = NFSD_MONOSEC + 5; 4151 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 4152 newusrp->lug_uid = nidp->nid_uid; 4153 thp = NFSUSERHASH(newusrp->lug_uid); 4154 mtx_assert(&thp->mtx, MA_OWNED); 4155 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 4156 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 4157 mtx_assert(&thp->mtx, MA_OWNED); 4158 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 4159 atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1); 4160 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 4161 newusrp->lug_gid = nidp->nid_gid; 4162 thp = NFSGROUPHASH(newusrp->lug_gid); 4163 mtx_assert(&thp->mtx, MA_OWNED); 4164 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 4165 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 4166 mtx_assert(&thp->mtx, MA_OWNED); 4167 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 4168 atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1); 4169 } else { 4170 if (newusrp->lug_cred != NULL) 4171 crfree(newusrp->lug_cred); 4172 free(newusrp, M_NFSUSERGROUP); 4173 } 4174 4175 /* 4176 * Once per second, allow one thread to trim the cache. 4177 */ 4178 if (lasttime < NFSD_MONOSEC && 4179 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) { 4180 /* 4181 * First, unlock the single mutexes, so that all entries 4182 * can be locked and any LOR is avoided. 4183 */ 4184 if (hp_name != NULL) { 4185 mtx_unlock(&hp_name->mtx); 4186 hp_name = NULL; 4187 } 4188 if (hp_idnum != NULL) { 4189 mtx_unlock(&hp_idnum->mtx); 4190 hp_idnum = NULL; 4191 } 4192 4193 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID | 4194 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) { 4195 if (username_locked == 0) { 4196 for (i = 0; i < nfsrv_lughashsize; i++) 4197 mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx); 4198 username_locked = 1; 4199 } 4200 KASSERT(user_locked == 0, 4201 ("nfssvc_idname: user_locked")); 4202 for (i = 0; i < nfsrv_lughashsize; i++) 4203 mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx); 4204 user_locked = 1; 4205 for (i = 0; i < nfsrv_lughashsize; i++) { 4206 TAILQ_FOREACH_SAFE(usrp, 4207 &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash, 4208 nusrp) 4209 if (usrp->lug_expiry < NFSD_MONOSEC) 4210 nfsrv_removeuser(usrp, 1); 4211 } 4212 for (i = 0; i < nfsrv_lughashsize; i++) { 4213 /* 4214 * Trim the cache using an approximate LRU 4215 * algorithm. This code deletes the least 4216 * recently used entry on each hash list. 4217 */ 4218 if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax)) 4219 break; 4220 usrp = TAILQ_FIRST(&NFSD_VNET(nfsuserhash)[i].lughead); 4221 if (usrp != NULL) 4222 nfsrv_removeuser(usrp, 1); 4223 } 4224 } else { 4225 if (groupname_locked == 0) { 4226 for (i = 0; i < nfsrv_lughashsize; i++) 4227 mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx); 4228 groupname_locked = 1; 4229 } 4230 KASSERT(group_locked == 0, 4231 ("nfssvc_idname: group_locked")); 4232 for (i = 0; i < nfsrv_lughashsize; i++) 4233 mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx); 4234 group_locked = 1; 4235 for (i = 0; i < nfsrv_lughashsize; i++) { 4236 TAILQ_FOREACH_SAFE(usrp, 4237 &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash, 4238 nusrp) 4239 if (usrp->lug_expiry < NFSD_MONOSEC) 4240 nfsrv_removeuser(usrp, 0); 4241 } 4242 for (i = 0; i < nfsrv_lughashsize; i++) { 4243 /* 4244 * Trim the cache using an approximate LRU 4245 * algorithm. This code deletes the least 4246 * recently user entry on each hash list. 4247 */ 4248 if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax)) 4249 break; 4250 usrp = TAILQ_FIRST(&NFSD_VNET(nfsgrouphash)[i].lughead); 4251 if (usrp != NULL) 4252 nfsrv_removeuser(usrp, 0); 4253 } 4254 } 4255 lasttime = NFSD_MONOSEC; 4256 atomic_store_rel_int(&onethread, 0); 4257 } 4258 4259 /* Now, unlock all locked mutexes. */ 4260 if (hp_idnum != NULL) 4261 mtx_unlock(&hp_idnum->mtx); 4262 if (hp_name != NULL) 4263 mtx_unlock(&hp_name->mtx); 4264 if (user_locked != 0) 4265 for (i = 0; i < nfsrv_lughashsize; i++) 4266 mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx); 4267 if (username_locked != 0) 4268 for (i = 0; i < nfsrv_lughashsize; i++) 4269 mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx); 4270 if (group_locked != 0) 4271 for (i = 0; i < nfsrv_lughashsize; i++) 4272 mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx); 4273 if (groupname_locked != 0) 4274 for (i = 0; i < nfsrv_lughashsize; i++) 4275 mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx); 4276 out: 4277 NFSEXITCODE(error); 4278 return (error); 4279 } 4280 4281 /* 4282 * Remove a user/group name element. 4283 */ 4284 static void 4285 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser) 4286 { 4287 struct nfsrv_lughash *hp; 4288 4289 if (isuser != 0) { 4290 hp = NFSUSERHASH(usrp->lug_uid); 4291 mtx_assert(&hp->mtx, MA_OWNED); 4292 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4293 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen); 4294 mtx_assert(&hp->mtx, MA_OWNED); 4295 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 4296 } else { 4297 hp = NFSGROUPHASH(usrp->lug_gid); 4298 mtx_assert(&hp->mtx, MA_OWNED); 4299 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4300 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen); 4301 mtx_assert(&hp->mtx, MA_OWNED); 4302 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 4303 } 4304 atomic_add_int(&NFSD_VNET(nfsrv_usercnt), -1); 4305 if (usrp->lug_cred != NULL) 4306 crfree(usrp->lug_cred); 4307 free(usrp, M_NFSUSERGROUP); 4308 } 4309 4310 /* 4311 * Free up all the allocations related to the name<-->id cache. 4312 * This function should only be called when the nfsuserd daemon isn't 4313 * running, since it doesn't do any locking. 4314 * This function is meant to be called when a vnet jail is destroyed. 4315 */ 4316 void 4317 nfsrv_cleanusergroup(void) 4318 { 4319 struct nfsrv_lughash *hp, *hp2; 4320 struct nfsusrgrp *nusrp, *usrp; 4321 int i; 4322 4323 if (NFSD_VNET(nfsuserhash) == NULL) 4324 return; 4325 4326 for (i = 0; i < nfsrv_lughashsize; i++) { 4327 hp = &NFSD_VNET(nfsuserhash)[i]; 4328 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 4329 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4330 hp2 = NFSUSERNAMEHASH(usrp->lug_name, 4331 usrp->lug_namelen); 4332 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 4333 if (usrp->lug_cred != NULL) 4334 crfree(usrp->lug_cred); 4335 free(usrp, M_NFSUSERGROUP); 4336 } 4337 hp = &NFSD_VNET(nfsgrouphash)[i]; 4338 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 4339 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4340 hp2 = NFSGROUPNAMEHASH(usrp->lug_name, 4341 usrp->lug_namelen); 4342 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 4343 if (usrp->lug_cred != NULL) 4344 crfree(usrp->lug_cred); 4345 free(usrp, M_NFSUSERGROUP); 4346 } 4347 mtx_destroy(&NFSD_VNET(nfsuserhash)[i].mtx); 4348 mtx_destroy(&NFSD_VNET(nfsusernamehash)[i].mtx); 4349 mtx_destroy(&NFSD_VNET(nfsgroupnamehash)[i].mtx); 4350 mtx_destroy(&NFSD_VNET(nfsgrouphash)[i].mtx); 4351 } 4352 free(NFSD_VNET(nfsuserhash), M_NFSUSERGROUP); 4353 free(NFSD_VNET(nfsusernamehash), M_NFSUSERGROUP); 4354 free(NFSD_VNET(nfsgrouphash), M_NFSUSERGROUP); 4355 free(NFSD_VNET(nfsgroupnamehash), M_NFSUSERGROUP); 4356 free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING); 4357 } 4358 4359 /* 4360 * This function scans a byte string and checks for UTF-8 compliance. 4361 * It returns 0 if it conforms and NFSERR_INVAL if not. 4362 */ 4363 int 4364 nfsrv_checkutf8(u_int8_t *cp, int len) 4365 { 4366 u_int32_t val = 0x0; 4367 int cnt = 0, gotd = 0, shift = 0; 4368 u_int8_t byte; 4369 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 4370 int error = 0; 4371 4372 /* 4373 * Here are what the variables are used for: 4374 * val - the calculated value of a multibyte char, used to check 4375 * that it was coded with the correct range 4376 * cnt - the number of 10xxxxxx bytes to follow 4377 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 4378 * shift - lower order bits of range (ie. "val >> shift" should 4379 * not be 0, in other words, dividing by the lower bound 4380 * of the range should get a non-zero value) 4381 * byte - used to calculate cnt 4382 */ 4383 while (len > 0) { 4384 if (cnt > 0) { 4385 /* This handles the 10xxxxxx bytes */ 4386 if ((*cp & 0xc0) != 0x80 || 4387 (gotd && (*cp & 0x20))) { 4388 error = NFSERR_INVAL; 4389 goto out; 4390 } 4391 gotd = 0; 4392 val <<= 6; 4393 val |= (*cp & 0x3f); 4394 cnt--; 4395 if (cnt == 0 && (val >> shift) == 0x0) { 4396 error = NFSERR_INVAL; 4397 goto out; 4398 } 4399 } else if (*cp & 0x80) { 4400 /* first byte of multi byte char */ 4401 byte = *cp; 4402 while ((byte & 0x40) && cnt < 6) { 4403 cnt++; 4404 byte <<= 1; 4405 } 4406 if (cnt == 0 || cnt == 6) { 4407 error = NFSERR_INVAL; 4408 goto out; 4409 } 4410 val = (*cp & (0x3f >> cnt)); 4411 shift = utf8_shift[cnt - 1]; 4412 if (cnt == 2 && val == 0xd) 4413 /* Check for the 0xd800-0xdfff case */ 4414 gotd = 1; 4415 } 4416 cp++; 4417 len--; 4418 } 4419 if (cnt > 0) 4420 error = NFSERR_INVAL; 4421 4422 out: 4423 NFSEXITCODE(error); 4424 return (error); 4425 } 4426 4427 /* 4428 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 4429 * strings, one with the root path in it and the other with the list of 4430 * locations. The list is in the same format as is found in nfr_refs. 4431 * It is a "," separated list of entries, where each of them is of the 4432 * form <server>:<rootpath>. For example 4433 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 4434 * The nilp argument is set to 1 for the special case of a null fs_root 4435 * and an empty server list. 4436 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 4437 * number of xdr bytes parsed in sump. 4438 */ 4439 static int 4440 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 4441 int *sump, int *nilp) 4442 { 4443 u_int32_t *tl; 4444 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 4445 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 4446 struct list { 4447 SLIST_ENTRY(list) next; 4448 int len; 4449 u_char host[1]; 4450 } *lsp, *nlsp; 4451 SLIST_HEAD(, list) head; 4452 4453 *fsrootp = NULL; 4454 *srvp = NULL; 4455 *nilp = 0; 4456 4457 /* 4458 * Get the fs_root path and check for the special case of null path 4459 * and 0 length server list. 4460 */ 4461 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4462 len = fxdr_unsigned(int, *tl); 4463 if (len < 0 || len > 10240) { 4464 error = NFSERR_BADXDR; 4465 goto nfsmout; 4466 } 4467 if (len == 0) { 4468 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4469 if (*tl != 0) { 4470 error = NFSERR_BADXDR; 4471 goto nfsmout; 4472 } 4473 *nilp = 1; 4474 *sump = 2 * NFSX_UNSIGNED; 4475 error = 0; 4476 goto nfsmout; 4477 } 4478 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 4479 error = nfsrv_mtostr(nd, cp, len); 4480 if (!error) { 4481 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4482 cnt = fxdr_unsigned(int, *tl); 4483 if (cnt <= 0) 4484 error = NFSERR_BADXDR; 4485 } 4486 if (error) 4487 goto nfsmout; 4488 4489 /* 4490 * Now, loop through the location list and make up the srvlist. 4491 */ 4492 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 4493 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 4494 slen = 1024; 4495 siz = 0; 4496 for (i = 0; i < cnt; i++) { 4497 SLIST_INIT(&head); 4498 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4499 nsrv = fxdr_unsigned(int, *tl); 4500 if (nsrv <= 0) { 4501 error = NFSERR_BADXDR; 4502 goto nfsmout; 4503 } 4504 4505 /* 4506 * Handle the first server by putting it in the srvstr. 4507 */ 4508 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4509 len = fxdr_unsigned(int, *tl); 4510 if (len <= 0 || len > 1024) { 4511 error = NFSERR_BADXDR; 4512 goto nfsmout; 4513 } 4514 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 4515 if (cp3 != cp2) { 4516 *cp3++ = ','; 4517 siz++; 4518 } 4519 error = nfsrv_mtostr(nd, cp3, len); 4520 if (error) 4521 goto nfsmout; 4522 cp3 += len; 4523 *cp3++ = ':'; 4524 siz += (len + 1); 4525 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 4526 for (j = 1; j < nsrv; j++) { 4527 /* 4528 * Yuck, put them in an slist and process them later. 4529 */ 4530 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4531 len = fxdr_unsigned(int, *tl); 4532 if (len <= 0 || len > 1024) { 4533 error = NFSERR_BADXDR; 4534 goto nfsmout; 4535 } 4536 lsp = (struct list *)malloc(sizeof (struct list) 4537 + len, M_TEMP, M_WAITOK); 4538 error = nfsrv_mtostr(nd, lsp->host, len); 4539 if (error) 4540 goto nfsmout; 4541 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 4542 lsp->len = len; 4543 SLIST_INSERT_HEAD(&head, lsp, next); 4544 } 4545 4546 /* 4547 * Finally, we can get the path. 4548 */ 4549 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4550 len = fxdr_unsigned(int, *tl); 4551 if (len <= 0 || len > 1024) { 4552 error = NFSERR_BADXDR; 4553 goto nfsmout; 4554 } 4555 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 4556 error = nfsrv_mtostr(nd, cp3, len); 4557 if (error) 4558 goto nfsmout; 4559 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 4560 str = cp3; 4561 stringlen = len; 4562 cp3 += len; 4563 siz += len; 4564 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 4565 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 4566 &cp2, &cp3, &slen); 4567 *cp3++ = ','; 4568 NFSBCOPY(lsp->host, cp3, lsp->len); 4569 cp3 += lsp->len; 4570 *cp3++ = ':'; 4571 NFSBCOPY(str, cp3, stringlen); 4572 cp3 += stringlen; 4573 *cp3 = '\0'; 4574 siz += (lsp->len + stringlen + 2); 4575 free(lsp, M_TEMP); 4576 } 4577 } 4578 *fsrootp = cp; 4579 *srvp = cp2; 4580 *sump = xdrsum; 4581 NFSEXITCODE2(0, nd); 4582 return (0); 4583 nfsmout: 4584 if (cp != NULL) 4585 free(cp, M_NFSSTRING); 4586 if (cp2 != NULL) 4587 free(cp2, M_NFSSTRING); 4588 NFSEXITCODE2(error, nd); 4589 return (error); 4590 } 4591 4592 /* 4593 * Make the malloc'd space large enough. This is a pain, but the xdr 4594 * doesn't set an upper bound on the side, so... 4595 */ 4596 static void 4597 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 4598 { 4599 u_char *cp; 4600 int i; 4601 4602 if (siz <= *slenp) 4603 return; 4604 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 4605 NFSBCOPY(*cpp, cp, *slenp); 4606 free(*cpp, M_NFSSTRING); 4607 i = *cpp2 - *cpp; 4608 *cpp = cp; 4609 *cpp2 = cp + i; 4610 *slenp = siz + 1024; 4611 } 4612 4613 /* 4614 * Initialize the reply header data structures. 4615 */ 4616 void 4617 nfsrvd_rephead(struct nfsrv_descript *nd) 4618 { 4619 struct mbuf *mreq; 4620 4621 if ((nd->nd_flag & ND_EXTPG) != 0) { 4622 mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK); 4623 nd->nd_mreq = nd->nd_mb = mreq; 4624 nd->nd_bpos = (char *)(void *) 4625 PHYS_TO_DMAP(mreq->m_epg_pa[0]); 4626 nd->nd_bextpg = 0; 4627 nd->nd_bextpgsiz = PAGE_SIZE; 4628 } else { 4629 /* 4630 * If this is a big reply, use a cluster. 4631 */ 4632 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 4633 nfs_bigreply[nd->nd_procnum]) { 4634 NFSMCLGET(mreq, M_WAITOK); 4635 nd->nd_mreq = mreq; 4636 nd->nd_mb = mreq; 4637 } else { 4638 NFSMGET(mreq); 4639 nd->nd_mreq = mreq; 4640 nd->nd_mb = mreq; 4641 } 4642 nd->nd_bpos = mtod(mreq, char *); 4643 mreq->m_len = 0; 4644 } 4645 4646 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 4647 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 4648 } 4649 4650 /* 4651 * Lock a socket against others. 4652 * Currently used to serialize connect/disconnect attempts. 4653 */ 4654 int 4655 newnfs_sndlock(int *flagp) 4656 { 4657 struct timespec ts; 4658 4659 NFSLOCKSOCK(); 4660 while (*flagp & NFSR_SNDLOCK) { 4661 *flagp |= NFSR_WANTSND; 4662 ts.tv_sec = 0; 4663 ts.tv_nsec = 0; 4664 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 4665 PZERO - 1, "nfsndlck", &ts); 4666 } 4667 *flagp |= NFSR_SNDLOCK; 4668 NFSUNLOCKSOCK(); 4669 return (0); 4670 } 4671 4672 /* 4673 * Unlock the stream socket for others. 4674 */ 4675 void 4676 newnfs_sndunlock(int *flagp) 4677 { 4678 4679 NFSLOCKSOCK(); 4680 if ((*flagp & NFSR_SNDLOCK) == 0) 4681 panic("nfs sndunlock"); 4682 *flagp &= ~NFSR_SNDLOCK; 4683 if (*flagp & NFSR_WANTSND) { 4684 *flagp &= ~NFSR_WANTSND; 4685 wakeup((caddr_t)flagp); 4686 } 4687 NFSUNLOCKSOCK(); 4688 } 4689 4690 int 4691 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin, 4692 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp) 4693 { 4694 struct in_addr saddr; 4695 uint32_t portnum, *tl; 4696 int i, j, k; 4697 sa_family_t af = AF_UNSPEC; 4698 char addr[64], protocol[5], *cp; 4699 int cantparse = 0, error = 0; 4700 uint16_t portv; 4701 4702 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4703 i = fxdr_unsigned(int, *tl); 4704 if (i >= 3 && i <= 4) { 4705 error = nfsrv_mtostr(nd, protocol, i); 4706 if (error) 4707 goto nfsmout; 4708 if (strcmp(protocol, "tcp") == 0) { 4709 af = AF_INET; 4710 *isudp = 0; 4711 } else if (strcmp(protocol, "udp") == 0) { 4712 af = AF_INET; 4713 *isudp = 1; 4714 } else if (strcmp(protocol, "tcp6") == 0) { 4715 af = AF_INET6; 4716 *isudp = 0; 4717 } else if (strcmp(protocol, "udp6") == 0) { 4718 af = AF_INET6; 4719 *isudp = 1; 4720 } else 4721 cantparse = 1; 4722 } else { 4723 cantparse = 1; 4724 if (i > 0) { 4725 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4726 if (error) 4727 goto nfsmout; 4728 } 4729 } 4730 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4731 i = fxdr_unsigned(int, *tl); 4732 if (i < 0) { 4733 error = NFSERR_BADXDR; 4734 goto nfsmout; 4735 } else if (cantparse == 0 && i >= 11 && i < 64) { 4736 /* 4737 * The shortest address is 11chars and the longest is < 64. 4738 */ 4739 error = nfsrv_mtostr(nd, addr, i); 4740 if (error) 4741 goto nfsmout; 4742 4743 /* Find the port# at the end and extract that. */ 4744 i = strlen(addr); 4745 k = 0; 4746 cp = &addr[i - 1]; 4747 /* Count back two '.'s from end to get port# field. */ 4748 for (j = 0; j < i; j++) { 4749 if (*cp == '.') { 4750 k++; 4751 if (k == 2) 4752 break; 4753 } 4754 cp--; 4755 } 4756 if (k == 2) { 4757 /* 4758 * The NFSv4 port# is appended as .N.N, where N is 4759 * a decimal # in the range 0-255, just like an inet4 4760 * address. Cheat and use inet_aton(), which will 4761 * return a Class A address and then shift the high 4762 * order 8bits over to convert it to the port#. 4763 */ 4764 *cp++ = '\0'; 4765 if (inet_aton(cp, &saddr) == 1) { 4766 portnum = ntohl(saddr.s_addr); 4767 portv = (uint16_t)((portnum >> 16) | 4768 (portnum & 0xff)); 4769 } else 4770 cantparse = 1; 4771 } else 4772 cantparse = 1; 4773 if (cantparse == 0) { 4774 if (af == AF_INET) { 4775 if (inet_pton(af, addr, &sin->sin_addr) == 1) { 4776 sin->sin_len = sizeof(*sin); 4777 sin->sin_family = AF_INET; 4778 sin->sin_port = htons(portv); 4779 *saf = af; 4780 return (0); 4781 } 4782 } else { 4783 if (inet_pton(af, addr, &sin6->sin6_addr) 4784 == 1) { 4785 sin6->sin6_len = sizeof(*sin6); 4786 sin6->sin6_family = AF_INET6; 4787 sin6->sin6_port = htons(portv); 4788 *saf = af; 4789 return (0); 4790 } 4791 } 4792 } 4793 } else { 4794 if (i > 0) { 4795 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4796 if (error) 4797 goto nfsmout; 4798 } 4799 } 4800 error = EPERM; 4801 nfsmout: 4802 return (error); 4803 } 4804 4805 /* 4806 * Handle an NFSv4.1 Sequence request for the session. 4807 * If reply != NULL, use it to return the cached reply, as required. 4808 * The client gets a cached reply via this call for callbacks, however the 4809 * server gets a cached reply via the nfsv4_seqsess_cacherep() call. 4810 */ 4811 int 4812 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 4813 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 4814 { 4815 struct mbuf *m; 4816 int error; 4817 4818 error = 0; 4819 if (reply != NULL) 4820 *reply = NULL; 4821 if (slotid > maxslot) 4822 return (NFSERR_BADSLOT); 4823 if (seqid == slots[slotid].nfssl_seq) { 4824 /* A retry. */ 4825 if (slots[slotid].nfssl_inprog != 0) 4826 error = NFSERR_DELAY; 4827 else if (slots[slotid].nfssl_reply != NULL) { 4828 if (reply != NULL) { 4829 m = m_copym(slots[slotid].nfssl_reply, 0, 4830 M_COPYALL, M_NOWAIT); 4831 if (m != NULL) 4832 *reply = m; 4833 else { 4834 *reply = slots[slotid].nfssl_reply; 4835 slots[slotid].nfssl_reply = NULL; 4836 } 4837 } 4838 slots[slotid].nfssl_inprog = 1; 4839 error = NFSERR_REPLYFROMCACHE; 4840 } else 4841 /* No reply cached, so just do it. */ 4842 slots[slotid].nfssl_inprog = 1; 4843 } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 4844 if (slots[slotid].nfssl_reply != NULL) 4845 m_freem(slots[slotid].nfssl_reply); 4846 slots[slotid].nfssl_reply = NULL; 4847 slots[slotid].nfssl_inprog = 1; 4848 slots[slotid].nfssl_seq++; 4849 } else 4850 error = NFSERR_SEQMISORDERED; 4851 return (error); 4852 } 4853 4854 /* 4855 * Cache this reply for the slot. 4856 * Use the "rep" argument to return the cached reply if repstat is set to 4857 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value. 4858 */ 4859 void 4860 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat, 4861 struct mbuf **rep) 4862 { 4863 struct mbuf *m; 4864 4865 if (repstat == NFSERR_REPLYFROMCACHE) { 4866 if (slots[slotid].nfssl_reply != NULL) { 4867 /* 4868 * We cannot sleep here, but copy will usually 4869 * succeed. 4870 */ 4871 m = m_copym(slots[slotid].nfssl_reply, 0, M_COPYALL, 4872 M_NOWAIT); 4873 if (m != NULL) 4874 *rep = m; 4875 else { 4876 /* 4877 * Multiple retries would be extremely rare, 4878 * so using the cached reply will likely 4879 * be ok. 4880 */ 4881 *rep = slots[slotid].nfssl_reply; 4882 slots[slotid].nfssl_reply = NULL; 4883 } 4884 } else 4885 *rep = NULL; 4886 } else { 4887 if (slots[slotid].nfssl_reply != NULL) 4888 m_freem(slots[slotid].nfssl_reply); 4889 slots[slotid].nfssl_reply = *rep; 4890 } 4891 slots[slotid].nfssl_inprog = 0; 4892 } 4893 4894 /* 4895 * Generate the xdr for an NFSv4.1 Sequence Operation. 4896 */ 4897 void 4898 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, 4899 struct nfsclsession *sep, int dont_replycache, struct ucred *cred) 4900 { 4901 uint32_t *tl, slotseq = 0; 4902 int error, maxslot, slotpos; 4903 uint8_t sessionid[NFSX_V4SESSIONID]; 4904 4905 if (cred != NULL) { 4906 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, 4907 &slotseq, sessionid, false); 4908 if (error == NFSERR_SEQMISORDERED) { 4909 /* If all slots are bad, Destroy the session. */ 4910 nfsrpc_destroysession(nmp, sep, cred, curthread); 4911 } 4912 } else 4913 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, 4914 &slotseq, sessionid, true); 4915 nd->nd_maxreq = sep->nfsess_maxreq; 4916 nd->nd_maxresp = sep->nfsess_maxresp; 4917 4918 /* Build the Sequence arguments. */ 4919 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 4920 nd->nd_sequence = tl; 4921 bcopy(sessionid, tl, NFSX_V4SESSIONID); 4922 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4923 nd->nd_slotseq = tl; 4924 if (error == 0) { 4925 nd->nd_flag |= ND_HASSLOTID; 4926 nd->nd_slotid = slotpos; 4927 *tl++ = txdr_unsigned(slotseq); 4928 *tl++ = txdr_unsigned(slotpos); 4929 *tl++ = txdr_unsigned(maxslot); 4930 if (dont_replycache == 0) 4931 *tl = newnfs_true; 4932 else 4933 *tl = newnfs_false; 4934 } else { 4935 /* 4936 * There are two errors and the rest of the session can 4937 * just be zeros. 4938 * NFSERR_BADSESSION: This bad session should just generate 4939 * the same error again when the RPC is retried. 4940 * ESTALE: A forced dismount is in progress and will cause the 4941 * RPC to fail later. 4942 */ 4943 *tl++ = 0; 4944 *tl++ = 0; 4945 *tl++ = 0; 4946 *tl = 0; 4947 } 4948 nd->nd_flag |= ND_HASSEQUENCE; 4949 } 4950 4951 /* 4952 * If fnd_init is true, ignore the badslots. 4953 * If fnd_init is false, return NFSERR_SEQMISORDERED if all slots are bad. 4954 */ 4955 int 4956 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep, 4957 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid, 4958 bool fnd_init) 4959 { 4960 int i, maxslot, slotpos; 4961 uint64_t bitval; 4962 bool fnd_ok; 4963 4964 /* Find an unused slot. */ 4965 slotpos = -1; 4966 maxslot = -1; 4967 mtx_lock(&sep->nfsess_mtx); 4968 do { 4969 if (nmp != NULL && sep->nfsess_defunct != 0) { 4970 /* Just return the bad session. */ 4971 bcopy(sep->nfsess_sessionid, sessionid, 4972 NFSX_V4SESSIONID); 4973 mtx_unlock(&sep->nfsess_mtx); 4974 return (NFSERR_BADSESSION); 4975 } 4976 fnd_ok = fnd_init; 4977 bitval = 1; 4978 for (i = 0; i < sep->nfsess_foreslots; i++) { 4979 if ((bitval & sep->nfsess_badslots) == 0 || fnd_init) { 4980 fnd_ok = true; 4981 if ((bitval & sep->nfsess_slots) == 0) { 4982 slotpos = i; 4983 sep->nfsess_slots |= bitval; 4984 sep->nfsess_slotseq[i]++; 4985 *slotseqp = sep->nfsess_slotseq[i]; 4986 break; 4987 } 4988 } 4989 bitval <<= 1; 4990 } 4991 if (slotpos == -1) { 4992 /* 4993 * If a forced dismount is in progress, just return. 4994 * This RPC attempt will fail when it calls 4995 * newnfs_request(). 4996 */ 4997 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) { 4998 mtx_unlock(&sep->nfsess_mtx); 4999 return (ESTALE); 5000 } 5001 /* Wake up once/sec, to check for a forced dismount. */ 5002 if (fnd_ok) 5003 mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 5004 PZERO, "nfsclseq", hz); 5005 } 5006 } while (slotpos == -1 && fnd_ok); 5007 /* 5008 * If all slots are bad, just return slot 0 and NFSERR_SEQMISORDERED. 5009 * The caller will do a DestroySession, so that the session's use 5010 * will get a NFSERR_BADSESSION reply from the server. 5011 */ 5012 if (!fnd_ok) 5013 slotpos = 0; 5014 5015 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 5016 bitval = 1; 5017 for (i = 0; i < 64; i++) { 5018 if ((bitval & sep->nfsess_slots) != 0) 5019 maxslot = i; 5020 bitval <<= 1; 5021 } 5022 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 5023 mtx_unlock(&sep->nfsess_mtx); 5024 *slotposp = slotpos; 5025 *maxslotp = maxslot; 5026 5027 if (!fnd_ok) 5028 return (NFSERR_SEQMISORDERED); 5029 return (0); 5030 } 5031 5032 /* 5033 * Free a session slot. 5034 */ 5035 void 5036 nfsv4_freeslot(struct nfsclsession *sep, int slot, bool resetseq) 5037 { 5038 uint64_t bitval; 5039 5040 bitval = 1; 5041 if (slot > 0) 5042 bitval <<= slot; 5043 mtx_lock(&sep->nfsess_mtx); 5044 if (resetseq) 5045 sep->nfsess_slotseq[slot]--; 5046 if ((bitval & sep->nfsess_slots) == 0) 5047 printf("freeing free slot!!\n"); 5048 sep->nfsess_slots &= ~bitval; 5049 wakeup(&sep->nfsess_slots); 5050 mtx_unlock(&sep->nfsess_mtx); 5051 } 5052 5053 /* 5054 * Search for a matching pnfsd DS, based on the nmp arg. 5055 * Return one if found, NULL otherwise. 5056 */ 5057 struct nfsdevice * 5058 nfsv4_findmirror(struct nfsmount *nmp) 5059 { 5060 struct nfsdevice *ds; 5061 5062 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED); 5063 /* 5064 * Search the DS server list for a match with nmp. 5065 */ 5066 if (nfsrv_devidcnt == 0) 5067 return (NULL); 5068 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) { 5069 if (ds->nfsdev_nmp == nmp) { 5070 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n"); 5071 break; 5072 } 5073 } 5074 return (ds); 5075 } 5076 5077 /* 5078 * Fill in the fields of "struct nfsrv_descript". 5079 */ 5080 void 5081 nfsm_set(struct nfsrv_descript *nd, u_int offs) 5082 { 5083 struct mbuf *m; 5084 int rlen; 5085 5086 m = nd->nd_mb; 5087 if ((m->m_flags & M_EXTPG) != 0) { 5088 nd->nd_bextpg = 0; 5089 while (offs > 0) { 5090 if (nd->nd_bextpg == 0) 5091 rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off); 5092 else 5093 rlen = m_epg_pagelen(m, nd->nd_bextpg, 0); 5094 if (offs <= rlen) 5095 break; 5096 offs -= rlen; 5097 nd->nd_bextpg++; 5098 if (nd->nd_bextpg == m->m_epg_npgs) { 5099 printf("nfsm_set: build offs " 5100 "out of range\n"); 5101 nd->nd_bextpg--; 5102 break; 5103 } 5104 } 5105 nd->nd_bpos = (char *)(void *) 5106 PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]); 5107 if (nd->nd_bextpg == 0) 5108 nd->nd_bpos += m->m_epg_1st_off; 5109 if (offs > 0) { 5110 nd->nd_bpos += offs; 5111 nd->nd_bextpgsiz = rlen - offs; 5112 } else if (nd->nd_bextpg == 0) 5113 nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off; 5114 else 5115 nd->nd_bextpgsiz = PAGE_SIZE; 5116 } else 5117 nd->nd_bpos = mtod(m, char *) + offs; 5118 } 5119 5120 /* 5121 * Grow a ext_pgs mbuf list. Either allocate another page or add 5122 * an mbuf to the list. 5123 */ 5124 struct mbuf * 5125 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg) 5126 { 5127 struct mbuf *mp; 5128 vm_page_t pg; 5129 5130 if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) { 5131 mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK); 5132 *bextpg = 0; 5133 m->m_next = mp; 5134 } else { 5135 pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP | 5136 VM_ALLOC_WIRED); 5137 m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg); 5138 *bextpg = m->m_epg_npgs; 5139 m->m_epg_npgs++; 5140 m->m_epg_last_len = 0; 5141 mp = m; 5142 } 5143 return (mp); 5144 } 5145 5146 /* 5147 * Do the NFSv4.1 Destroy Session. 5148 */ 5149 int 5150 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclsession *tsep, 5151 struct ucred *cred, NFSPROC_T *p) 5152 { 5153 uint32_t *tl; 5154 struct nfsrv_descript nfsd; 5155 struct nfsrv_descript *nd = &nfsd; 5156 int error; 5157 5158 if (tsep == NULL) 5159 tsep = nfsmnt_mdssession(nmp); 5160 if (tsep == NULL) 5161 return (0); 5162 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0, 5163 0, NULL); 5164 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 5165 bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID); 5166 nd->nd_flag |= ND_USEGSSNAME; 5167 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5168 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5169 if (error != 0) 5170 return (error); 5171 error = nd->nd_repstat; 5172 m_freem(nd->nd_mrep); 5173 return (error); 5174 } 5175