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