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