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