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