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