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