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