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