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