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