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