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