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