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