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