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, (caddr_t)&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, (caddr_t)&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, (caddr_t)&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 void *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 (void) nfsmsleep(&lp->nfslock_lock, mutex, 2284 PZERO - 1, "nfsv4lck", NULL); 2285 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) && 2286 lp->nfslock_usecnt == 0) { 2287 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 2288 lp->nfslock_lock |= NFSV4LOCK_LOCK; 2289 return (1); 2290 } 2291 } 2292 return (0); 2293 } 2294 2295 /* 2296 * Release the lock acquired by nfsv4_lock(). 2297 * The second argument is set to 1 to indicate the nfslock_usecnt should be 2298 * incremented, as well. 2299 */ 2300 void 2301 nfsv4_unlock(struct nfsv4lock *lp, int incref) 2302 { 2303 2304 lp->nfslock_lock &= ~NFSV4LOCK_LOCK; 2305 if (incref) 2306 lp->nfslock_usecnt++; 2307 nfsv4_wanted(lp); 2308 } 2309 2310 /* 2311 * Release a reference cnt. 2312 */ 2313 void 2314 nfsv4_relref(struct nfsv4lock *lp) 2315 { 2316 2317 if (lp->nfslock_usecnt <= 0) 2318 panic("nfsv4root ref cnt"); 2319 lp->nfslock_usecnt--; 2320 if (lp->nfslock_usecnt == 0) 2321 nfsv4_wanted(lp); 2322 } 2323 2324 /* 2325 * Get a reference cnt. 2326 * This function will wait for any exclusive lock to be released, but will 2327 * not wait for threads that want the exclusive lock. If priority needs 2328 * to be given to threads that need the exclusive lock, a call to nfsv4_lock() 2329 * with the 2nd argument == 0 should be done before calling nfsv4_getref(). 2330 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and 2331 * return without getting a refcnt for that case. 2332 */ 2333 void 2334 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex, 2335 struct mount *mp) 2336 { 2337 2338 if (isleptp) 2339 *isleptp = 0; 2340 2341 /* 2342 * Wait for a lock held. 2343 */ 2344 while (lp->nfslock_lock & NFSV4LOCK_LOCK) { 2345 if (mp != NULL && NFSCL_FORCEDISM(mp)) 2346 return; 2347 lp->nfslock_lock |= NFSV4LOCK_WANTED; 2348 if (isleptp) 2349 *isleptp = 1; 2350 (void) nfsmsleep(&lp->nfslock_lock, mutex, 2351 PZERO - 1, "nfsv4gr", NULL); 2352 } 2353 if (mp != NULL && NFSCL_FORCEDISM(mp)) 2354 return; 2355 2356 lp->nfslock_usecnt++; 2357 } 2358 2359 /* 2360 * Get a reference as above, but return failure instead of sleeping if 2361 * an exclusive lock is held. 2362 */ 2363 int 2364 nfsv4_getref_nonblock(struct nfsv4lock *lp) 2365 { 2366 2367 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0) 2368 return (0); 2369 2370 lp->nfslock_usecnt++; 2371 return (1); 2372 } 2373 2374 /* 2375 * Test for a lock. Return 1 if locked, 0 otherwise. 2376 */ 2377 int 2378 nfsv4_testlock(struct nfsv4lock *lp) 2379 { 2380 2381 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 && 2382 lp->nfslock_usecnt == 0) 2383 return (0); 2384 return (1); 2385 } 2386 2387 /* 2388 * Wake up anyone sleeping, waiting for this lock. 2389 */ 2390 static void 2391 nfsv4_wanted(struct nfsv4lock *lp) 2392 { 2393 2394 if (lp->nfslock_lock & NFSV4LOCK_WANTED) { 2395 lp->nfslock_lock &= ~NFSV4LOCK_WANTED; 2396 wakeup((caddr_t)&lp->nfslock_lock); 2397 } 2398 } 2399 2400 /* 2401 * Copy a string from an mbuf list into a character array. 2402 * Return EBADRPC if there is an mbuf error, 2403 * 0 otherwise. 2404 */ 2405 int 2406 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) 2407 { 2408 char *cp; 2409 int xfer, len; 2410 struct mbuf *mp; 2411 int rem, error = 0; 2412 2413 mp = nd->nd_md; 2414 cp = nd->nd_dpos; 2415 len = mtod(mp, caddr_t) + mp->m_len - cp; 2416 rem = NFSM_RNDUP(siz) - siz; 2417 while (siz > 0) { 2418 if (len > siz) 2419 xfer = siz; 2420 else 2421 xfer = len; 2422 NFSBCOPY(cp, str, xfer); 2423 str += xfer; 2424 siz -= xfer; 2425 if (siz > 0) { 2426 mp = mp->m_next; 2427 if (mp == NULL) { 2428 error = EBADRPC; 2429 goto out; 2430 } 2431 cp = mtod(mp, caddr_t); 2432 len = mp->m_len; 2433 } else { 2434 cp += xfer; 2435 len -= xfer; 2436 } 2437 } 2438 *str = '\0'; 2439 nd->nd_dpos = cp; 2440 nd->nd_md = mp; 2441 if (rem > 0) { 2442 if (len < rem) 2443 error = nfsm_advance(nd, rem, len); 2444 else 2445 nd->nd_dpos += rem; 2446 } 2447 2448 out: 2449 NFSEXITCODE2(error, nd); 2450 return (error); 2451 } 2452 2453 /* 2454 * Fill in the attributes as marked by the bitmap (V4). 2455 */ 2456 int 2457 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, 2458 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror, 2459 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram, 2460 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno, 2461 struct statfs *pnfssf) 2462 { 2463 int bitpos, retnum = 0; 2464 u_int32_t *tl; 2465 int siz, prefixnum, error; 2466 u_char *cp, namestr[NFSV4_SMALLSTR]; 2467 nfsattrbit_t attrbits, retbits; 2468 nfsattrbit_t *retbitp = &retbits; 2469 u_int32_t freenum, *retnump; 2470 u_int64_t uquad; 2471 struct statfs *fs; 2472 struct nfsfsinfo fsinf; 2473 struct timespec temptime; 2474 NFSACL_T *aclp, *naclp = NULL; 2475 size_t atsiz; 2476 bool xattrsupp; 2477 #ifdef QUOTA 2478 struct dqblk dqb; 2479 uid_t savuid; 2480 #endif 2481 2482 /* 2483 * First, set the bits that can be filled and get fsinfo. 2484 */ 2485 NFSSET_ATTRBIT(retbitp, attrbitp); 2486 /* 2487 * If both p and cred are NULL, it is a client side setattr call. 2488 * If both p and cred are not NULL, it is a server side reply call. 2489 * If p is not NULL and cred is NULL, it is a client side callback 2490 * reply call. 2491 */ 2492 if (p == NULL && cred == NULL) { 2493 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd); 2494 aclp = saclp; 2495 } else { 2496 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd); 2497 naclp = acl_alloc(M_WAITOK); 2498 aclp = naclp; 2499 } 2500 nfsvno_getfs(&fsinf, isdgram); 2501 #ifndef APPLE 2502 /* 2503 * Get the VFS_STATFS(), since some attributes need them. 2504 */ 2505 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 2506 if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 2507 error = VFS_STATFS(mp, fs); 2508 if (error != 0) { 2509 if (reterr) { 2510 nd->nd_repstat = NFSERR_ACCES; 2511 free(fs, M_STATFS); 2512 return (0); 2513 } 2514 NFSCLRSTATFS_ATTRBIT(retbitp); 2515 } 2516 } 2517 #endif 2518 2519 /* 2520 * And the NFSv4 ACL... 2521 */ 2522 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 2523 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2524 supports_nfsv4acls == 0))) { 2525 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 2526 } 2527 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 2528 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2529 supports_nfsv4acls == 0)) { 2530 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2531 } else if (naclp != NULL) { 2532 if (NFSVOPLOCK(vp, LK_SHARED) == 0) { 2533 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); 2534 if (error == 0) 2535 error = VOP_GETACL(vp, ACL_TYPE_NFS4, 2536 naclp, cred, p); 2537 NFSVOPUNLOCK(vp); 2538 } else 2539 error = NFSERR_PERM; 2540 if (error != 0) { 2541 if (reterr) { 2542 nd->nd_repstat = NFSERR_ACCES; 2543 free(fs, M_STATFS); 2544 return (0); 2545 } 2546 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2547 } 2548 } 2549 } 2550 2551 /* Check to see if Extended Attributes are supported. */ 2552 xattrsupp = false; 2553 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) { 2554 if (NFSVOPLOCK(vp, LK_SHARED) == 0) { 2555 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, 2556 "xxx", NULL, &atsiz, cred, p); 2557 NFSVOPUNLOCK(vp); 2558 if (error != EOPNOTSUPP) 2559 xattrsupp = true; 2560 } 2561 } 2562 2563 /* 2564 * Put out the attribute bitmap for the ones being filled in 2565 * and get the field for the number of attributes returned. 2566 */ 2567 prefixnum = nfsrv_putattrbit(nd, retbitp); 2568 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 2569 prefixnum += NFSX_UNSIGNED; 2570 2571 /* 2572 * Now, loop around filling in the attributes for each bit set. 2573 */ 2574 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 2575 if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 2576 switch (bitpos) { 2577 case NFSATTRBIT_SUPPORTEDATTRS: 2578 NFSSETSUPP_ATTRBIT(&attrbits, nd); 2579 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 2580 && supports_nfsv4acls == 0)) { 2581 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 2582 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 2583 } 2584 retnum += nfsrv_putattrbit(nd, &attrbits); 2585 break; 2586 case NFSATTRBIT_TYPE: 2587 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2588 *tl = vtonfsv34_type(vap->va_type); 2589 retnum += NFSX_UNSIGNED; 2590 break; 2591 case NFSATTRBIT_FHEXPIRETYPE: 2592 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2593 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2594 retnum += NFSX_UNSIGNED; 2595 break; 2596 case NFSATTRBIT_CHANGE: 2597 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2598 txdr_hyper(vap->va_filerev, tl); 2599 retnum += NFSX_HYPER; 2600 break; 2601 case NFSATTRBIT_SIZE: 2602 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2603 txdr_hyper(vap->va_size, tl); 2604 retnum += NFSX_HYPER; 2605 break; 2606 case NFSATTRBIT_LINKSUPPORT: 2607 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2608 if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2609 *tl = newnfs_true; 2610 else 2611 *tl = newnfs_false; 2612 retnum += NFSX_UNSIGNED; 2613 break; 2614 case NFSATTRBIT_SYMLINKSUPPORT: 2615 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2616 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2617 *tl = newnfs_true; 2618 else 2619 *tl = newnfs_false; 2620 retnum += NFSX_UNSIGNED; 2621 break; 2622 case NFSATTRBIT_NAMEDATTR: 2623 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2624 *tl = newnfs_false; 2625 retnum += NFSX_UNSIGNED; 2626 break; 2627 case NFSATTRBIT_FSID: 2628 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2629 *tl++ = 0; 2630 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]); 2631 *tl++ = 0; 2632 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]); 2633 retnum += NFSX_V4FSID; 2634 break; 2635 case NFSATTRBIT_UNIQUEHANDLES: 2636 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2637 *tl = newnfs_true; 2638 retnum += NFSX_UNSIGNED; 2639 break; 2640 case NFSATTRBIT_LEASETIME: 2641 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2642 *tl = txdr_unsigned(nfsrv_lease); 2643 retnum += NFSX_UNSIGNED; 2644 break; 2645 case NFSATTRBIT_RDATTRERROR: 2646 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2647 *tl = txdr_unsigned(rderror); 2648 retnum += NFSX_UNSIGNED; 2649 break; 2650 /* 2651 * Recommended Attributes. (Only the supported ones.) 2652 */ 2653 case NFSATTRBIT_ACL: 2654 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2655 break; 2656 case NFSATTRBIT_ACLSUPPORT: 2657 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2658 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2659 retnum += NFSX_UNSIGNED; 2660 break; 2661 case NFSATTRBIT_CANSETTIME: 2662 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2663 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2664 *tl = newnfs_true; 2665 else 2666 *tl = newnfs_false; 2667 retnum += NFSX_UNSIGNED; 2668 break; 2669 case NFSATTRBIT_CASEINSENSITIVE: 2670 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2671 *tl = newnfs_false; 2672 retnum += NFSX_UNSIGNED; 2673 break; 2674 case NFSATTRBIT_CASEPRESERVING: 2675 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2676 *tl = newnfs_true; 2677 retnum += NFSX_UNSIGNED; 2678 break; 2679 case NFSATTRBIT_CHOWNRESTRICTED: 2680 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2681 *tl = newnfs_true; 2682 retnum += NFSX_UNSIGNED; 2683 break; 2684 case NFSATTRBIT_FILEHANDLE: 2685 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2686 break; 2687 case NFSATTRBIT_FILEID: 2688 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2689 uquad = vap->va_fileid; 2690 txdr_hyper(uquad, tl); 2691 retnum += NFSX_HYPER; 2692 break; 2693 case NFSATTRBIT_FILESAVAIL: 2694 /* 2695 * Check quota and use min(quota, f_ffree). 2696 */ 2697 freenum = fs->f_ffree; 2698 #ifdef QUOTA 2699 /* 2700 * ufs_quotactl() insists that the uid argument 2701 * equal p_ruid for non-root quota access, so 2702 * we'll just make sure that's the case. 2703 */ 2704 savuid = p->p_cred->p_ruid; 2705 p->p_cred->p_ruid = cred->cr_uid; 2706 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2707 cred->cr_uid, (caddr_t)&dqb)) 2708 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2709 freenum); 2710 p->p_cred->p_ruid = savuid; 2711 #endif /* QUOTA */ 2712 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2713 *tl++ = 0; 2714 *tl = txdr_unsigned(freenum); 2715 retnum += NFSX_HYPER; 2716 break; 2717 case NFSATTRBIT_FILESFREE: 2718 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2719 *tl++ = 0; 2720 *tl = txdr_unsigned(fs->f_ffree); 2721 retnum += NFSX_HYPER; 2722 break; 2723 case NFSATTRBIT_FILESTOTAL: 2724 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2725 *tl++ = 0; 2726 *tl = txdr_unsigned(fs->f_files); 2727 retnum += NFSX_HYPER; 2728 break; 2729 case NFSATTRBIT_FSLOCATIONS: 2730 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2731 *tl++ = 0; 2732 *tl = 0; 2733 retnum += 2 * NFSX_UNSIGNED; 2734 break; 2735 case NFSATTRBIT_HOMOGENEOUS: 2736 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2737 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2738 *tl = newnfs_true; 2739 else 2740 *tl = newnfs_false; 2741 retnum += NFSX_UNSIGNED; 2742 break; 2743 case NFSATTRBIT_MAXFILESIZE: 2744 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2745 uquad = NFSRV_MAXFILESIZE; 2746 txdr_hyper(uquad, tl); 2747 retnum += NFSX_HYPER; 2748 break; 2749 case NFSATTRBIT_MAXLINK: 2750 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2751 *tl = txdr_unsigned(NFS_LINK_MAX); 2752 retnum += NFSX_UNSIGNED; 2753 break; 2754 case NFSATTRBIT_MAXNAME: 2755 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2756 *tl = txdr_unsigned(NFS_MAXNAMLEN); 2757 retnum += NFSX_UNSIGNED; 2758 break; 2759 case NFSATTRBIT_MAXREAD: 2760 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2761 *tl++ = 0; 2762 *tl = txdr_unsigned(fsinf.fs_rtmax); 2763 retnum += NFSX_HYPER; 2764 break; 2765 case NFSATTRBIT_MAXWRITE: 2766 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2767 *tl++ = 0; 2768 *tl = txdr_unsigned(fsinf.fs_wtmax); 2769 retnum += NFSX_HYPER; 2770 break; 2771 case NFSATTRBIT_MODE: 2772 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2773 *tl = vtonfsv34_mode(vap->va_mode); 2774 retnum += NFSX_UNSIGNED; 2775 break; 2776 case NFSATTRBIT_NOTRUNC: 2777 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2778 *tl = newnfs_true; 2779 retnum += NFSX_UNSIGNED; 2780 break; 2781 case NFSATTRBIT_NUMLINKS: 2782 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2783 *tl = txdr_unsigned(vap->va_nlink); 2784 retnum += NFSX_UNSIGNED; 2785 break; 2786 case NFSATTRBIT_OWNER: 2787 cp = namestr; 2788 nfsv4_uidtostr(vap->va_uid, &cp, &siz); 2789 retnum += nfsm_strtom(nd, cp, siz); 2790 if (cp != namestr) 2791 free(cp, M_NFSSTRING); 2792 break; 2793 case NFSATTRBIT_OWNERGROUP: 2794 cp = namestr; 2795 nfsv4_gidtostr(vap->va_gid, &cp, &siz); 2796 retnum += nfsm_strtom(nd, cp, siz); 2797 if (cp != namestr) 2798 free(cp, M_NFSSTRING); 2799 break; 2800 case NFSATTRBIT_QUOTAHARD: 2801 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA)) 2802 freenum = fs->f_bfree; 2803 else 2804 freenum = fs->f_bavail; 2805 #ifdef QUOTA 2806 /* 2807 * ufs_quotactl() insists that the uid argument 2808 * equal p_ruid for non-root quota access, so 2809 * we'll just make sure that's the case. 2810 */ 2811 savuid = p->p_cred->p_ruid; 2812 p->p_cred->p_ruid = cred->cr_uid; 2813 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2814 cred->cr_uid, (caddr_t)&dqb)) 2815 freenum = min(dqb.dqb_bhardlimit, freenum); 2816 p->p_cred->p_ruid = savuid; 2817 #endif /* QUOTA */ 2818 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2819 uquad = (u_int64_t)freenum; 2820 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize); 2821 txdr_hyper(uquad, tl); 2822 retnum += NFSX_HYPER; 2823 break; 2824 case NFSATTRBIT_QUOTASOFT: 2825 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA)) 2826 freenum = fs->f_bfree; 2827 else 2828 freenum = fs->f_bavail; 2829 #ifdef QUOTA 2830 /* 2831 * ufs_quotactl() insists that the uid argument 2832 * equal p_ruid for non-root quota access, so 2833 * we'll just make sure that's the case. 2834 */ 2835 savuid = p->p_cred->p_ruid; 2836 p->p_cred->p_ruid = cred->cr_uid; 2837 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2838 cred->cr_uid, (caddr_t)&dqb)) 2839 freenum = min(dqb.dqb_bsoftlimit, freenum); 2840 p->p_cred->p_ruid = savuid; 2841 #endif /* QUOTA */ 2842 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2843 uquad = (u_int64_t)freenum; 2844 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize); 2845 txdr_hyper(uquad, tl); 2846 retnum += NFSX_HYPER; 2847 break; 2848 case NFSATTRBIT_QUOTAUSED: 2849 freenum = 0; 2850 #ifdef QUOTA 2851 /* 2852 * ufs_quotactl() insists that the uid argument 2853 * equal p_ruid for non-root quota access, so 2854 * we'll just make sure that's the case. 2855 */ 2856 savuid = p->p_cred->p_ruid; 2857 p->p_cred->p_ruid = cred->cr_uid; 2858 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2859 cred->cr_uid, (caddr_t)&dqb)) 2860 freenum = dqb.dqb_curblocks; 2861 p->p_cred->p_ruid = savuid; 2862 #endif /* QUOTA */ 2863 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2864 uquad = (u_int64_t)freenum; 2865 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize); 2866 txdr_hyper(uquad, tl); 2867 retnum += NFSX_HYPER; 2868 break; 2869 case NFSATTRBIT_RAWDEV: 2870 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2871 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2872 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2873 retnum += NFSX_V4SPECDATA; 2874 break; 2875 case NFSATTRBIT_SPACEAVAIL: 2876 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2877 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) { 2878 if (pnfssf != NULL) 2879 uquad = (u_int64_t)pnfssf->f_bfree; 2880 else 2881 uquad = (u_int64_t)fs->f_bfree; 2882 } else { 2883 if (pnfssf != NULL) 2884 uquad = (u_int64_t)pnfssf->f_bavail; 2885 else 2886 uquad = (u_int64_t)fs->f_bavail; 2887 } 2888 if (pnfssf != NULL) 2889 uquad *= pnfssf->f_bsize; 2890 else 2891 uquad *= fs->f_bsize; 2892 txdr_hyper(uquad, tl); 2893 retnum += NFSX_HYPER; 2894 break; 2895 case NFSATTRBIT_SPACEFREE: 2896 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2897 if (pnfssf != NULL) { 2898 uquad = (u_int64_t)pnfssf->f_bfree; 2899 uquad *= pnfssf->f_bsize; 2900 } else { 2901 uquad = (u_int64_t)fs->f_bfree; 2902 uquad *= fs->f_bsize; 2903 } 2904 txdr_hyper(uquad, tl); 2905 retnum += NFSX_HYPER; 2906 break; 2907 case NFSATTRBIT_SPACETOTAL: 2908 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2909 if (pnfssf != NULL) { 2910 uquad = (u_int64_t)pnfssf->f_blocks; 2911 uquad *= pnfssf->f_bsize; 2912 } else { 2913 uquad = (u_int64_t)fs->f_blocks; 2914 uquad *= fs->f_bsize; 2915 } 2916 txdr_hyper(uquad, tl); 2917 retnum += NFSX_HYPER; 2918 break; 2919 case NFSATTRBIT_SPACEUSED: 2920 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2921 txdr_hyper(vap->va_bytes, tl); 2922 retnum += NFSX_HYPER; 2923 break; 2924 case NFSATTRBIT_TIMEACCESS: 2925 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2926 txdr_nfsv4time(&vap->va_atime, tl); 2927 retnum += NFSX_V4TIME; 2928 break; 2929 case NFSATTRBIT_TIMEACCESSSET: 2930 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2931 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2932 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2933 txdr_nfsv4time(&vap->va_atime, tl); 2934 retnum += NFSX_V4SETTIME; 2935 } else { 2936 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2937 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2938 retnum += NFSX_UNSIGNED; 2939 } 2940 break; 2941 case NFSATTRBIT_TIMEDELTA: 2942 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2943 temptime.tv_sec = 0; 2944 temptime.tv_nsec = 1000000000 / hz; 2945 txdr_nfsv4time(&temptime, tl); 2946 retnum += NFSX_V4TIME; 2947 break; 2948 case NFSATTRBIT_TIMEMETADATA: 2949 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2950 txdr_nfsv4time(&vap->va_ctime, tl); 2951 retnum += NFSX_V4TIME; 2952 break; 2953 case NFSATTRBIT_TIMEMODIFY: 2954 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2955 txdr_nfsv4time(&vap->va_mtime, tl); 2956 retnum += NFSX_V4TIME; 2957 break; 2958 case NFSATTRBIT_TIMECREATE: 2959 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2960 txdr_nfsv4time(&vap->va_birthtime, tl); 2961 retnum += NFSX_V4TIME; 2962 break; 2963 case NFSATTRBIT_TIMEMODIFYSET: 2964 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2965 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2966 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2967 txdr_nfsv4time(&vap->va_mtime, tl); 2968 retnum += NFSX_V4SETTIME; 2969 } else { 2970 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2971 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2972 retnum += NFSX_UNSIGNED; 2973 } 2974 break; 2975 case NFSATTRBIT_MOUNTEDONFILEID: 2976 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2977 if (at_root != 0) 2978 uquad = mounted_on_fileno; 2979 else 2980 uquad = vap->va_fileid; 2981 txdr_hyper(uquad, tl); 2982 retnum += NFSX_HYPER; 2983 break; 2984 case NFSATTRBIT_SUPPATTREXCLCREAT: 2985 NFSSETSUPP_ATTRBIT(&attrbits, nd); 2986 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd); 2987 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); 2988 retnum += nfsrv_putattrbit(nd, &attrbits); 2989 break; 2990 case NFSATTRBIT_FSLAYOUTTYPE: 2991 case NFSATTRBIT_LAYOUTTYPE: 2992 if (nfsrv_devidcnt == 0) 2993 siz = 1; 2994 else 2995 siz = 2; 2996 if (siz == 2) { 2997 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2998 *tl++ = txdr_unsigned(1); /* One entry. */ 2999 if (nfsrv_doflexfile != 0 || 3000 nfsrv_maxpnfsmirror > 1) 3001 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE); 3002 else 3003 *tl = txdr_unsigned( 3004 NFSLAYOUT_NFSV4_1_FILES); 3005 } else { 3006 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3007 *tl = 0; 3008 } 3009 retnum += siz * NFSX_UNSIGNED; 3010 break; 3011 case NFSATTRBIT_LAYOUTALIGNMENT: 3012 case NFSATTRBIT_LAYOUTBLKSIZE: 3013 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3014 *tl = txdr_unsigned(NFS_SRVMAXIO); 3015 retnum += NFSX_UNSIGNED; 3016 break; 3017 case NFSATTRBIT_XATTRSUPPORT: 3018 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3019 if (xattrsupp) 3020 *tl = newnfs_true; 3021 else 3022 *tl = newnfs_false; 3023 retnum += NFSX_UNSIGNED; 3024 break; 3025 default: 3026 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 3027 } 3028 } 3029 } 3030 if (naclp != NULL) 3031 acl_free(naclp); 3032 free(fs, M_STATFS); 3033 *retnump = txdr_unsigned(retnum); 3034 return (retnum + prefixnum); 3035 } 3036 3037 /* 3038 * Put the attribute bits onto an mbuf list. 3039 * Return the number of bytes of output generated. 3040 */ 3041 int 3042 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 3043 { 3044 u_int32_t *tl; 3045 int cnt, i, bytesize; 3046 3047 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 3048 if (attrbitp->bits[cnt - 1]) 3049 break; 3050 bytesize = (cnt + 1) * NFSX_UNSIGNED; 3051 NFSM_BUILD(tl, u_int32_t *, bytesize); 3052 *tl++ = txdr_unsigned(cnt); 3053 for (i = 0; i < cnt; i++) 3054 *tl++ = txdr_unsigned(attrbitp->bits[i]); 3055 return (bytesize); 3056 } 3057 3058 /* 3059 * Convert a uid to a string. 3060 * If the lookup fails, just output the digits. 3061 * uid - the user id 3062 * cpp - points to a buffer of size NFSV4_SMALLSTR 3063 * (malloc a larger one, as required) 3064 * retlenp - pointer to length to be returned 3065 */ 3066 void 3067 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp) 3068 { 3069 int i; 3070 struct nfsusrgrp *usrp; 3071 u_char *cp = *cpp; 3072 uid_t tmp; 3073 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 3074 struct nfsrv_lughash *hp; 3075 3076 cnt = 0; 3077 tryagain: 3078 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) { 3079 /* 3080 * Always map nfsrv_defaultuid to "nobody". 3081 */ 3082 if (uid == nfsrv_defaultuid) { 3083 i = nfsrv_dnsnamelen + 7; 3084 if (i > len) { 3085 if (len > NFSV4_SMALLSTR) 3086 free(cp, M_NFSSTRING); 3087 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3088 *cpp = cp; 3089 len = i; 3090 goto tryagain; 3091 } 3092 *retlenp = i; 3093 NFSBCOPY("nobody@", cp, 7); 3094 cp += 7; 3095 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 3096 return; 3097 } 3098 hasampersand = 0; 3099 hp = NFSUSERHASH(uid); 3100 mtx_lock(&hp->mtx); 3101 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 3102 if (usrp->lug_uid == uid) { 3103 if (usrp->lug_expiry < NFSD_MONOSEC) 3104 break; 3105 /* 3106 * If the name doesn't already have an '@' 3107 * in it, append @domainname to it. 3108 */ 3109 for (i = 0; i < usrp->lug_namelen; i++) { 3110 if (usrp->lug_name[i] == '@') { 3111 hasampersand = 1; 3112 break; 3113 } 3114 } 3115 if (hasampersand) 3116 i = usrp->lug_namelen; 3117 else 3118 i = usrp->lug_namelen + 3119 nfsrv_dnsnamelen + 1; 3120 if (i > len) { 3121 mtx_unlock(&hp->mtx); 3122 if (len > NFSV4_SMALLSTR) 3123 free(cp, M_NFSSTRING); 3124 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3125 *cpp = cp; 3126 len = i; 3127 goto tryagain; 3128 } 3129 *retlenp = i; 3130 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 3131 if (!hasampersand) { 3132 cp += usrp->lug_namelen; 3133 *cp++ = '@'; 3134 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 3135 } 3136 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3137 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 3138 lug_numhash); 3139 mtx_unlock(&hp->mtx); 3140 return; 3141 } 3142 } 3143 mtx_unlock(&hp->mtx); 3144 cnt++; 3145 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL); 3146 if (ret == 0 && cnt < 2) 3147 goto tryagain; 3148 } 3149 3150 /* 3151 * No match, just return a string of digits. 3152 */ 3153 tmp = uid; 3154 i = 0; 3155 while (tmp || i == 0) { 3156 tmp /= 10; 3157 i++; 3158 } 3159 len = (i > len) ? len : i; 3160 *retlenp = len; 3161 cp += (len - 1); 3162 tmp = uid; 3163 for (i = 0; i < len; i++) { 3164 *cp-- = '0' + (tmp % 10); 3165 tmp /= 10; 3166 } 3167 return; 3168 } 3169 3170 /* 3171 * Get a credential for the uid with the server's group list. 3172 * If none is found, just return the credential passed in after 3173 * logging a warning message. 3174 */ 3175 struct ucred * 3176 nfsrv_getgrpscred(struct ucred *oldcred) 3177 { 3178 struct nfsusrgrp *usrp; 3179 struct ucred *newcred; 3180 int cnt, ret; 3181 uid_t uid; 3182 struct nfsrv_lughash *hp; 3183 3184 cnt = 0; 3185 uid = oldcred->cr_uid; 3186 tryagain: 3187 if (nfsrv_dnsnamelen > 0) { 3188 hp = NFSUSERHASH(uid); 3189 mtx_lock(&hp->mtx); 3190 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 3191 if (usrp->lug_uid == uid) { 3192 if (usrp->lug_expiry < NFSD_MONOSEC) 3193 break; 3194 if (usrp->lug_cred != NULL) { 3195 newcred = crhold(usrp->lug_cred); 3196 crfree(oldcred); 3197 } else 3198 newcred = oldcred; 3199 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3200 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 3201 lug_numhash); 3202 mtx_unlock(&hp->mtx); 3203 return (newcred); 3204 } 3205 } 3206 mtx_unlock(&hp->mtx); 3207 cnt++; 3208 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL); 3209 if (ret == 0 && cnt < 2) 3210 goto tryagain; 3211 } 3212 return (oldcred); 3213 } 3214 3215 /* 3216 * Convert a string to a uid. 3217 * If no conversion is possible return NFSERR_BADOWNER, otherwise 3218 * return 0. 3219 * If this is called from a client side mount using AUTH_SYS and the 3220 * string is made up entirely of digits, just convert the string to 3221 * a number. 3222 */ 3223 int 3224 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp) 3225 { 3226 int i; 3227 char *cp, *endstr, *str0; 3228 struct nfsusrgrp *usrp; 3229 int cnt, ret; 3230 int error = 0; 3231 uid_t tuid; 3232 struct nfsrv_lughash *hp, *hp2; 3233 3234 if (len == 0) { 3235 error = NFSERR_BADOWNER; 3236 goto out; 3237 } 3238 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 3239 str0 = str; 3240 tuid = (uid_t)strtoul(str0, &endstr, 10); 3241 if ((endstr - str0) == len) { 3242 /* A numeric string. */ 3243 if ((nd->nd_flag & ND_KERBV) == 0 && 3244 ((nd->nd_flag & ND_NFSCL) != 0 || 3245 nfsd_enable_stringtouid != 0)) 3246 *uidp = tuid; 3247 else 3248 error = NFSERR_BADOWNER; 3249 goto out; 3250 } 3251 /* 3252 * Look for an '@'. 3253 */ 3254 cp = strchr(str0, '@'); 3255 if (cp != NULL) 3256 i = (int)(cp++ - str0); 3257 else 3258 i = len; 3259 3260 cnt = 0; 3261 tryagain: 3262 if (nfsrv_dnsnamelen > 0) { 3263 /* 3264 * If an '@' is found and the domain name matches, search for 3265 * the name with dns stripped off. 3266 * Mixed case alpahbetics will match for the domain name, but 3267 * all upper case will not. 3268 */ 3269 if (cnt == 0 && i < len && i > 0 && 3270 (len - 1 - i) == nfsrv_dnsnamelen && 3271 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 3272 len -= (nfsrv_dnsnamelen + 1); 3273 *(cp - 1) = '\0'; 3274 } 3275 3276 /* 3277 * Check for the special case of "nobody". 3278 */ 3279 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 3280 *uidp = nfsrv_defaultuid; 3281 error = 0; 3282 goto out; 3283 } 3284 3285 hp = NFSUSERNAMEHASH(str, len); 3286 mtx_lock(&hp->mtx); 3287 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 3288 if (usrp->lug_namelen == len && 3289 !NFSBCMP(usrp->lug_name, str, len)) { 3290 if (usrp->lug_expiry < NFSD_MONOSEC) 3291 break; 3292 hp2 = NFSUSERHASH(usrp->lug_uid); 3293 mtx_lock(&hp2->mtx); 3294 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 3295 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 3296 lug_numhash); 3297 *uidp = usrp->lug_uid; 3298 mtx_unlock(&hp2->mtx); 3299 mtx_unlock(&hp->mtx); 3300 error = 0; 3301 goto out; 3302 } 3303 } 3304 mtx_unlock(&hp->mtx); 3305 cnt++; 3306 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 3307 str); 3308 if (ret == 0 && cnt < 2) 3309 goto tryagain; 3310 } 3311 error = NFSERR_BADOWNER; 3312 3313 out: 3314 NFSEXITCODE(error); 3315 return (error); 3316 } 3317 3318 /* 3319 * Convert a gid to a string. 3320 * gid - the group id 3321 * cpp - points to a buffer of size NFSV4_SMALLSTR 3322 * (malloc a larger one, as required) 3323 * retlenp - pointer to length to be returned 3324 */ 3325 void 3326 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp) 3327 { 3328 int i; 3329 struct nfsusrgrp *usrp; 3330 u_char *cp = *cpp; 3331 gid_t tmp; 3332 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 3333 struct nfsrv_lughash *hp; 3334 3335 cnt = 0; 3336 tryagain: 3337 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) { 3338 /* 3339 * Always map nfsrv_defaultgid to "nogroup". 3340 */ 3341 if (gid == nfsrv_defaultgid) { 3342 i = nfsrv_dnsnamelen + 8; 3343 if (i > len) { 3344 if (len > NFSV4_SMALLSTR) 3345 free(cp, M_NFSSTRING); 3346 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3347 *cpp = cp; 3348 len = i; 3349 goto tryagain; 3350 } 3351 *retlenp = i; 3352 NFSBCOPY("nogroup@", cp, 8); 3353 cp += 8; 3354 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 3355 return; 3356 } 3357 hasampersand = 0; 3358 hp = NFSGROUPHASH(gid); 3359 mtx_lock(&hp->mtx); 3360 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 3361 if (usrp->lug_gid == gid) { 3362 if (usrp->lug_expiry < NFSD_MONOSEC) 3363 break; 3364 /* 3365 * If the name doesn't already have an '@' 3366 * in it, append @domainname to it. 3367 */ 3368 for (i = 0; i < usrp->lug_namelen; i++) { 3369 if (usrp->lug_name[i] == '@') { 3370 hasampersand = 1; 3371 break; 3372 } 3373 } 3374 if (hasampersand) 3375 i = usrp->lug_namelen; 3376 else 3377 i = usrp->lug_namelen + 3378 nfsrv_dnsnamelen + 1; 3379 if (i > len) { 3380 mtx_unlock(&hp->mtx); 3381 if (len > NFSV4_SMALLSTR) 3382 free(cp, M_NFSSTRING); 3383 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3384 *cpp = cp; 3385 len = i; 3386 goto tryagain; 3387 } 3388 *retlenp = i; 3389 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 3390 if (!hasampersand) { 3391 cp += usrp->lug_namelen; 3392 *cp++ = '@'; 3393 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 3394 } 3395 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3396 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 3397 lug_numhash); 3398 mtx_unlock(&hp->mtx); 3399 return; 3400 } 3401 } 3402 mtx_unlock(&hp->mtx); 3403 cnt++; 3404 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL); 3405 if (ret == 0 && cnt < 2) 3406 goto tryagain; 3407 } 3408 3409 /* 3410 * No match, just return a string of digits. 3411 */ 3412 tmp = gid; 3413 i = 0; 3414 while (tmp || i == 0) { 3415 tmp /= 10; 3416 i++; 3417 } 3418 len = (i > len) ? len : i; 3419 *retlenp = len; 3420 cp += (len - 1); 3421 tmp = gid; 3422 for (i = 0; i < len; i++) { 3423 *cp-- = '0' + (tmp % 10); 3424 tmp /= 10; 3425 } 3426 return; 3427 } 3428 3429 /* 3430 * Convert a string to a gid. 3431 * If no conversion is possible return NFSERR_BADOWNER, otherwise 3432 * return 0. 3433 * If this is called from a client side mount using AUTH_SYS and the 3434 * string is made up entirely of digits, just convert the string to 3435 * a number. 3436 */ 3437 int 3438 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp) 3439 { 3440 int i; 3441 char *cp, *endstr, *str0; 3442 struct nfsusrgrp *usrp; 3443 int cnt, ret; 3444 int error = 0; 3445 gid_t tgid; 3446 struct nfsrv_lughash *hp, *hp2; 3447 3448 if (len == 0) { 3449 error = NFSERR_BADOWNER; 3450 goto out; 3451 } 3452 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 3453 str0 = str; 3454 tgid = (gid_t)strtoul(str0, &endstr, 10); 3455 if ((endstr - str0) == len) { 3456 /* A numeric string. */ 3457 if ((nd->nd_flag & ND_KERBV) == 0 && 3458 ((nd->nd_flag & ND_NFSCL) != 0 || 3459 nfsd_enable_stringtouid != 0)) 3460 *gidp = tgid; 3461 else 3462 error = NFSERR_BADOWNER; 3463 goto out; 3464 } 3465 /* 3466 * Look for an '@'. 3467 */ 3468 cp = strchr(str0, '@'); 3469 if (cp != NULL) 3470 i = (int)(cp++ - str0); 3471 else 3472 i = len; 3473 3474 cnt = 0; 3475 tryagain: 3476 if (nfsrv_dnsnamelen > 0) { 3477 /* 3478 * If an '@' is found and the dns name matches, search for the 3479 * name with the dns stripped off. 3480 */ 3481 if (cnt == 0 && i < len && i > 0 && 3482 (len - 1 - i) == nfsrv_dnsnamelen && 3483 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 3484 len -= (nfsrv_dnsnamelen + 1); 3485 *(cp - 1) = '\0'; 3486 } 3487 3488 /* 3489 * Check for the special case of "nogroup". 3490 */ 3491 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 3492 *gidp = nfsrv_defaultgid; 3493 error = 0; 3494 goto out; 3495 } 3496 3497 hp = NFSGROUPNAMEHASH(str, len); 3498 mtx_lock(&hp->mtx); 3499 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 3500 if (usrp->lug_namelen == len && 3501 !NFSBCMP(usrp->lug_name, str, len)) { 3502 if (usrp->lug_expiry < NFSD_MONOSEC) 3503 break; 3504 hp2 = NFSGROUPHASH(usrp->lug_gid); 3505 mtx_lock(&hp2->mtx); 3506 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 3507 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 3508 lug_numhash); 3509 *gidp = usrp->lug_gid; 3510 mtx_unlock(&hp2->mtx); 3511 mtx_unlock(&hp->mtx); 3512 error = 0; 3513 goto out; 3514 } 3515 } 3516 mtx_unlock(&hp->mtx); 3517 cnt++; 3518 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 3519 str); 3520 if (ret == 0 && cnt < 2) 3521 goto tryagain; 3522 } 3523 error = NFSERR_BADOWNER; 3524 3525 out: 3526 NFSEXITCODE(error); 3527 return (error); 3528 } 3529 3530 /* 3531 * Cmp len chars, allowing mixed case in the first argument to match lower 3532 * case in the second, but not if the first argument is all upper case. 3533 * Return 0 for a match, 1 otherwise. 3534 */ 3535 static int 3536 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 3537 { 3538 int i; 3539 u_char tmp; 3540 int fndlower = 0; 3541 3542 for (i = 0; i < len; i++) { 3543 if (*cp >= 'A' && *cp <= 'Z') { 3544 tmp = *cp++ + ('a' - 'A'); 3545 } else { 3546 tmp = *cp++; 3547 if (tmp >= 'a' && tmp <= 'z') 3548 fndlower = 1; 3549 } 3550 if (tmp != *cp2++) 3551 return (1); 3552 } 3553 if (fndlower) 3554 return (0); 3555 else 3556 return (1); 3557 } 3558 3559 /* 3560 * Set the port for the nfsuserd. 3561 */ 3562 int 3563 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p) 3564 { 3565 struct nfssockreq *rp; 3566 #ifdef INET 3567 struct sockaddr_in *ad; 3568 #endif 3569 #ifdef INET6 3570 struct sockaddr_in6 *ad6; 3571 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT; 3572 #endif 3573 int error; 3574 3575 NFSLOCKNAMEID(); 3576 if (nfsrv_nfsuserd != NOTRUNNING) { 3577 NFSUNLOCKNAMEID(); 3578 error = EPERM; 3579 goto out; 3580 } 3581 nfsrv_nfsuserd = STARTSTOP; 3582 /* 3583 * Set up the socket record and connect. 3584 * Set nr_client NULL before unlocking, just to ensure that no other 3585 * process/thread/core will use a bogus old value. This could only 3586 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is 3587 * broken. 3588 */ 3589 rp = &nfsrv_nfsuserdsock; 3590 rp->nr_client = NULL; 3591 NFSUNLOCKNAMEID(); 3592 rp->nr_sotype = SOCK_DGRAM; 3593 rp->nr_soproto = IPPROTO_UDP; 3594 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 3595 rp->nr_cred = NULL; 3596 rp->nr_prog = RPCPROG_NFSUSERD; 3597 error = 0; 3598 switch (nargs->nuserd_family) { 3599 #ifdef INET 3600 case AF_INET: 3601 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME, 3602 M_WAITOK | M_ZERO); 3603 ad = (struct sockaddr_in *)rp->nr_nam; 3604 ad->sin_len = sizeof(struct sockaddr_in); 3605 ad->sin_family = AF_INET; 3606 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 3607 ad->sin_port = nargs->nuserd_port; 3608 break; 3609 #endif 3610 #ifdef INET6 3611 case AF_INET6: 3612 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 3613 M_WAITOK | M_ZERO); 3614 ad6 = (struct sockaddr_in6 *)rp->nr_nam; 3615 ad6->sin6_len = sizeof(struct sockaddr_in6); 3616 ad6->sin6_family = AF_INET6; 3617 ad6->sin6_addr = in6loopback; 3618 ad6->sin6_port = nargs->nuserd_port; 3619 break; 3620 #endif 3621 default: 3622 error = ENXIO; 3623 } 3624 rp->nr_vers = RPCNFSUSERD_VERS; 3625 if (error == 0) 3626 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false); 3627 if (error == 0) { 3628 NFSLOCKNAMEID(); 3629 nfsrv_nfsuserd = RUNNING; 3630 NFSUNLOCKNAMEID(); 3631 } else { 3632 free(rp->nr_nam, M_SONAME); 3633 NFSLOCKNAMEID(); 3634 nfsrv_nfsuserd = NOTRUNNING; 3635 NFSUNLOCKNAMEID(); 3636 } 3637 out: 3638 NFSEXITCODE(error); 3639 return (error); 3640 } 3641 3642 /* 3643 * Delete the nfsuserd port. 3644 */ 3645 void 3646 nfsrv_nfsuserddelport(void) 3647 { 3648 3649 NFSLOCKNAMEID(); 3650 if (nfsrv_nfsuserd != RUNNING) { 3651 NFSUNLOCKNAMEID(); 3652 return; 3653 } 3654 nfsrv_nfsuserd = STARTSTOP; 3655 /* Wait for all upcalls to complete. */ 3656 while (nfsrv_userdupcalls > 0) 3657 msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS, 3658 "nfsupcalls", 0); 3659 NFSUNLOCKNAMEID(); 3660 newnfs_disconnect(&nfsrv_nfsuserdsock); 3661 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME); 3662 NFSLOCKNAMEID(); 3663 nfsrv_nfsuserd = NOTRUNNING; 3664 NFSUNLOCKNAMEID(); 3665 } 3666 3667 /* 3668 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 3669 * name<-->id cache. 3670 * Returns 0 upon success, non-zero otherwise. 3671 */ 3672 static int 3673 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name) 3674 { 3675 u_int32_t *tl; 3676 struct nfsrv_descript *nd; 3677 int len; 3678 struct nfsrv_descript nfsd; 3679 struct ucred *cred; 3680 int error; 3681 3682 NFSLOCKNAMEID(); 3683 if (nfsrv_nfsuserd != RUNNING) { 3684 NFSUNLOCKNAMEID(); 3685 error = EPERM; 3686 goto out; 3687 } 3688 /* 3689 * Maintain a count of upcalls in progress, so that nfsrv_X() 3690 * can wait until no upcalls are in progress. 3691 */ 3692 nfsrv_userdupcalls++; 3693 NFSUNLOCKNAMEID(); 3694 KASSERT(nfsrv_userdupcalls > 0, 3695 ("nfsrv_getuser: non-positive upcalls")); 3696 nd = &nfsd; 3697 cred = newnfs_getcred(); 3698 nd->nd_flag = ND_GSSINITREPLY; 3699 nfsrvd_rephead(nd); 3700 3701 nd->nd_procnum = procnum; 3702 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3703 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3704 if (procnum == RPCNFSUSERD_GETUID) 3705 *tl = txdr_unsigned(uid); 3706 else 3707 *tl = txdr_unsigned(gid); 3708 } else { 3709 len = strlen(name); 3710 (void) nfsm_strtom(nd, name, len); 3711 } 3712 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 3713 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL); 3714 NFSLOCKNAMEID(); 3715 if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP) 3716 wakeup(&nfsrv_userdupcalls); 3717 NFSUNLOCKNAMEID(); 3718 NFSFREECRED(cred); 3719 if (!error) { 3720 m_freem(nd->nd_mrep); 3721 error = nd->nd_repstat; 3722 } 3723 out: 3724 NFSEXITCODE(error); 3725 return (error); 3726 } 3727 3728 /* 3729 * This function is called from the nfssvc(2) system call, to update the 3730 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3731 */ 3732 int 3733 nfssvc_idname(struct nfsd_idargs *nidp) 3734 { 3735 struct nfsusrgrp *nusrp, *usrp, *newusrp; 3736 struct nfsrv_lughash *hp_name, *hp_idnum, *thp; 3737 int i, group_locked, groupname_locked, user_locked, username_locked; 3738 int error = 0; 3739 u_char *cp; 3740 gid_t *grps; 3741 struct ucred *cr; 3742 static int onethread = 0; 3743 static time_t lasttime = 0; 3744 3745 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) { 3746 error = EINVAL; 3747 goto out; 3748 } 3749 if (nidp->nid_flag & NFSID_INITIALIZE) { 3750 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); 3751 error = copyin(nidp->nid_name, cp, nidp->nid_namelen); 3752 if (error != 0) { 3753 free(cp, M_NFSSTRING); 3754 goto out; 3755 } 3756 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) { 3757 /* 3758 * Free up all the old stuff and reinitialize hash 3759 * lists. All mutexes for both lists must be locked, 3760 * with the user/group name ones before the uid/gid 3761 * ones, to avoid a LOR. 3762 */ 3763 for (i = 0; i < nfsrv_lughashsize; i++) 3764 mtx_lock(&nfsusernamehash[i].mtx); 3765 for (i = 0; i < nfsrv_lughashsize; i++) 3766 mtx_lock(&nfsuserhash[i].mtx); 3767 for (i = 0; i < nfsrv_lughashsize; i++) 3768 TAILQ_FOREACH_SAFE(usrp, 3769 &nfsuserhash[i].lughead, lug_numhash, nusrp) 3770 nfsrv_removeuser(usrp, 1); 3771 for (i = 0; i < nfsrv_lughashsize; i++) 3772 mtx_unlock(&nfsuserhash[i].mtx); 3773 for (i = 0; i < nfsrv_lughashsize; i++) 3774 mtx_unlock(&nfsusernamehash[i].mtx); 3775 for (i = 0; i < nfsrv_lughashsize; i++) 3776 mtx_lock(&nfsgroupnamehash[i].mtx); 3777 for (i = 0; i < nfsrv_lughashsize; i++) 3778 mtx_lock(&nfsgrouphash[i].mtx); 3779 for (i = 0; i < nfsrv_lughashsize; i++) 3780 TAILQ_FOREACH_SAFE(usrp, 3781 &nfsgrouphash[i].lughead, lug_numhash, 3782 nusrp) 3783 nfsrv_removeuser(usrp, 0); 3784 for (i = 0; i < nfsrv_lughashsize; i++) 3785 mtx_unlock(&nfsgrouphash[i].mtx); 3786 for (i = 0; i < nfsrv_lughashsize; i++) 3787 mtx_unlock(&nfsgroupnamehash[i].mtx); 3788 free(nfsrv_dnsname, M_NFSSTRING); 3789 nfsrv_dnsname = NULL; 3790 } 3791 if (nfsuserhash == NULL) { 3792 /* Allocate the hash tables. */ 3793 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) * 3794 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3795 M_ZERO); 3796 for (i = 0; i < nfsrv_lughashsize; i++) 3797 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash", 3798 NULL, MTX_DEF | MTX_DUPOK); 3799 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) * 3800 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3801 M_ZERO); 3802 for (i = 0; i < nfsrv_lughashsize; i++) 3803 mtx_init(&nfsusernamehash[i].mtx, 3804 "nfsusrhash", NULL, MTX_DEF | 3805 MTX_DUPOK); 3806 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) * 3807 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3808 M_ZERO); 3809 for (i = 0; i < nfsrv_lughashsize; i++) 3810 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash", 3811 NULL, MTX_DEF | MTX_DUPOK); 3812 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) * 3813 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3814 M_ZERO); 3815 for (i = 0; i < nfsrv_lughashsize; i++) 3816 mtx_init(&nfsgroupnamehash[i].mtx, 3817 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK); 3818 } 3819 /* (Re)initialize the list heads. */ 3820 for (i = 0; i < nfsrv_lughashsize; i++) 3821 TAILQ_INIT(&nfsuserhash[i].lughead); 3822 for (i = 0; i < nfsrv_lughashsize; i++) 3823 TAILQ_INIT(&nfsusernamehash[i].lughead); 3824 for (i = 0; i < nfsrv_lughashsize; i++) 3825 TAILQ_INIT(&nfsgrouphash[i].lughead); 3826 for (i = 0; i < nfsrv_lughashsize; i++) 3827 TAILQ_INIT(&nfsgroupnamehash[i].lughead); 3828 3829 /* 3830 * Put name in "DNS" string. 3831 */ 3832 nfsrv_dnsname = cp; 3833 nfsrv_defaultuid = nidp->nid_uid; 3834 nfsrv_defaultgid = nidp->nid_gid; 3835 nfsrv_usercnt = 0; 3836 nfsrv_usermax = nidp->nid_usermax; 3837 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen); 3838 goto out; 3839 } 3840 3841 /* 3842 * malloc the new one now, so any potential sleep occurs before 3843 * manipulation of the lists. 3844 */ 3845 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, 3846 M_NFSUSERGROUP, M_WAITOK | M_ZERO); 3847 error = copyin(nidp->nid_name, newusrp->lug_name, 3848 nidp->nid_namelen); 3849 if (error == 0 && nidp->nid_ngroup > 0 && 3850 (nidp->nid_flag & NFSID_ADDUID) != 0) { 3851 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP, 3852 M_WAITOK); 3853 error = copyin(nidp->nid_grps, grps, 3854 sizeof(gid_t) * nidp->nid_ngroup); 3855 if (error == 0) { 3856 /* 3857 * Create a credential just like svc_getcred(), 3858 * but using the group list provided. 3859 */ 3860 cr = crget(); 3861 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; 3862 crsetgroups(cr, nidp->nid_ngroup, grps); 3863 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; 3864 cr->cr_prison = &prison0; 3865 prison_hold(cr->cr_prison); 3866 #ifdef MAC 3867 mac_cred_associate_nfsd(cr); 3868 #endif 3869 newusrp->lug_cred = cr; 3870 } 3871 free(grps, M_TEMP); 3872 } 3873 if (error) { 3874 free(newusrp, M_NFSUSERGROUP); 3875 goto out; 3876 } 3877 newusrp->lug_namelen = nidp->nid_namelen; 3878 3879 /* 3880 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed 3881 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group. 3882 * The flags user_locked, username_locked, group_locked and 3883 * groupname_locked are set to indicate all of those hash lists are 3884 * locked. hp_name != NULL and hp_idnum != NULL indicates that 3885 * the respective one mutex is locked. 3886 */ 3887 user_locked = username_locked = group_locked = groupname_locked = 0; 3888 hp_name = hp_idnum = NULL; 3889 3890 /* 3891 * Delete old entries, as required. 3892 */ 3893 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3894 /* Must lock all username hash lists first, to avoid a LOR. */ 3895 for (i = 0; i < nfsrv_lughashsize; i++) 3896 mtx_lock(&nfsusernamehash[i].mtx); 3897 username_locked = 1; 3898 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3899 mtx_lock(&hp_idnum->mtx); 3900 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3901 nusrp) { 3902 if (usrp->lug_uid == nidp->nid_uid) 3903 nfsrv_removeuser(usrp, 1); 3904 } 3905 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3906 hp_name = NFSUSERNAMEHASH(newusrp->lug_name, 3907 newusrp->lug_namelen); 3908 mtx_lock(&hp_name->mtx); 3909 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3910 nusrp) { 3911 if (usrp->lug_namelen == newusrp->lug_namelen && 3912 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3913 usrp->lug_namelen)) { 3914 thp = NFSUSERHASH(usrp->lug_uid); 3915 mtx_lock(&thp->mtx); 3916 nfsrv_removeuser(usrp, 1); 3917 mtx_unlock(&thp->mtx); 3918 } 3919 } 3920 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3921 mtx_lock(&hp_idnum->mtx); 3922 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3923 /* Must lock all groupname hash lists first, to avoid a LOR. */ 3924 for (i = 0; i < nfsrv_lughashsize; i++) 3925 mtx_lock(&nfsgroupnamehash[i].mtx); 3926 groupname_locked = 1; 3927 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3928 mtx_lock(&hp_idnum->mtx); 3929 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3930 nusrp) { 3931 if (usrp->lug_gid == nidp->nid_gid) 3932 nfsrv_removeuser(usrp, 0); 3933 } 3934 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3935 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name, 3936 newusrp->lug_namelen); 3937 mtx_lock(&hp_name->mtx); 3938 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3939 nusrp) { 3940 if (usrp->lug_namelen == newusrp->lug_namelen && 3941 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3942 usrp->lug_namelen)) { 3943 thp = NFSGROUPHASH(usrp->lug_gid); 3944 mtx_lock(&thp->mtx); 3945 nfsrv_removeuser(usrp, 0); 3946 mtx_unlock(&thp->mtx); 3947 } 3948 } 3949 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3950 mtx_lock(&hp_idnum->mtx); 3951 } 3952 3953 /* 3954 * Now, we can add the new one. 3955 */ 3956 if (nidp->nid_usertimeout) 3957 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3958 else 3959 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3960 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3961 newusrp->lug_uid = nidp->nid_uid; 3962 thp = NFSUSERHASH(newusrp->lug_uid); 3963 mtx_assert(&thp->mtx, MA_OWNED); 3964 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3965 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3966 mtx_assert(&thp->mtx, MA_OWNED); 3967 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3968 atomic_add_int(&nfsrv_usercnt, 1); 3969 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3970 newusrp->lug_gid = nidp->nid_gid; 3971 thp = NFSGROUPHASH(newusrp->lug_gid); 3972 mtx_assert(&thp->mtx, MA_OWNED); 3973 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3974 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3975 mtx_assert(&thp->mtx, MA_OWNED); 3976 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3977 atomic_add_int(&nfsrv_usercnt, 1); 3978 } else { 3979 if (newusrp->lug_cred != NULL) 3980 crfree(newusrp->lug_cred); 3981 free(newusrp, M_NFSUSERGROUP); 3982 } 3983 3984 /* 3985 * Once per second, allow one thread to trim the cache. 3986 */ 3987 if (lasttime < NFSD_MONOSEC && 3988 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) { 3989 /* 3990 * First, unlock the single mutexes, so that all entries 3991 * can be locked and any LOR is avoided. 3992 */ 3993 if (hp_name != NULL) { 3994 mtx_unlock(&hp_name->mtx); 3995 hp_name = NULL; 3996 } 3997 if (hp_idnum != NULL) { 3998 mtx_unlock(&hp_idnum->mtx); 3999 hp_idnum = NULL; 4000 } 4001 4002 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID | 4003 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) { 4004 if (username_locked == 0) { 4005 for (i = 0; i < nfsrv_lughashsize; i++) 4006 mtx_lock(&nfsusernamehash[i].mtx); 4007 username_locked = 1; 4008 } 4009 KASSERT(user_locked == 0, 4010 ("nfssvc_idname: user_locked")); 4011 for (i = 0; i < nfsrv_lughashsize; i++) 4012 mtx_lock(&nfsuserhash[i].mtx); 4013 user_locked = 1; 4014 for (i = 0; i < nfsrv_lughashsize; i++) { 4015 TAILQ_FOREACH_SAFE(usrp, 4016 &nfsuserhash[i].lughead, lug_numhash, 4017 nusrp) 4018 if (usrp->lug_expiry < NFSD_MONOSEC) 4019 nfsrv_removeuser(usrp, 1); 4020 } 4021 for (i = 0; i < nfsrv_lughashsize; i++) { 4022 /* 4023 * Trim the cache using an approximate LRU 4024 * algorithm. This code deletes the least 4025 * recently used entry on each hash list. 4026 */ 4027 if (nfsrv_usercnt <= nfsrv_usermax) 4028 break; 4029 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead); 4030 if (usrp != NULL) 4031 nfsrv_removeuser(usrp, 1); 4032 } 4033 } else { 4034 if (groupname_locked == 0) { 4035 for (i = 0; i < nfsrv_lughashsize; i++) 4036 mtx_lock(&nfsgroupnamehash[i].mtx); 4037 groupname_locked = 1; 4038 } 4039 KASSERT(group_locked == 0, 4040 ("nfssvc_idname: group_locked")); 4041 for (i = 0; i < nfsrv_lughashsize; i++) 4042 mtx_lock(&nfsgrouphash[i].mtx); 4043 group_locked = 1; 4044 for (i = 0; i < nfsrv_lughashsize; i++) { 4045 TAILQ_FOREACH_SAFE(usrp, 4046 &nfsgrouphash[i].lughead, lug_numhash, 4047 nusrp) 4048 if (usrp->lug_expiry < NFSD_MONOSEC) 4049 nfsrv_removeuser(usrp, 0); 4050 } 4051 for (i = 0; i < nfsrv_lughashsize; i++) { 4052 /* 4053 * Trim the cache using an approximate LRU 4054 * algorithm. This code deletes the least 4055 * recently user entry on each hash list. 4056 */ 4057 if (nfsrv_usercnt <= nfsrv_usermax) 4058 break; 4059 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead); 4060 if (usrp != NULL) 4061 nfsrv_removeuser(usrp, 0); 4062 } 4063 } 4064 lasttime = NFSD_MONOSEC; 4065 atomic_store_rel_int(&onethread, 0); 4066 } 4067 4068 /* Now, unlock all locked mutexes. */ 4069 if (hp_idnum != NULL) 4070 mtx_unlock(&hp_idnum->mtx); 4071 if (hp_name != NULL) 4072 mtx_unlock(&hp_name->mtx); 4073 if (user_locked != 0) 4074 for (i = 0; i < nfsrv_lughashsize; i++) 4075 mtx_unlock(&nfsuserhash[i].mtx); 4076 if (username_locked != 0) 4077 for (i = 0; i < nfsrv_lughashsize; i++) 4078 mtx_unlock(&nfsusernamehash[i].mtx); 4079 if (group_locked != 0) 4080 for (i = 0; i < nfsrv_lughashsize; i++) 4081 mtx_unlock(&nfsgrouphash[i].mtx); 4082 if (groupname_locked != 0) 4083 for (i = 0; i < nfsrv_lughashsize; i++) 4084 mtx_unlock(&nfsgroupnamehash[i].mtx); 4085 out: 4086 NFSEXITCODE(error); 4087 return (error); 4088 } 4089 4090 /* 4091 * Remove a user/group name element. 4092 */ 4093 static void 4094 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser) 4095 { 4096 struct nfsrv_lughash *hp; 4097 4098 if (isuser != 0) { 4099 hp = NFSUSERHASH(usrp->lug_uid); 4100 mtx_assert(&hp->mtx, MA_OWNED); 4101 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4102 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen); 4103 mtx_assert(&hp->mtx, MA_OWNED); 4104 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 4105 } else { 4106 hp = NFSGROUPHASH(usrp->lug_gid); 4107 mtx_assert(&hp->mtx, MA_OWNED); 4108 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4109 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen); 4110 mtx_assert(&hp->mtx, MA_OWNED); 4111 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 4112 } 4113 atomic_add_int(&nfsrv_usercnt, -1); 4114 if (usrp->lug_cred != NULL) 4115 crfree(usrp->lug_cred); 4116 free(usrp, M_NFSUSERGROUP); 4117 } 4118 4119 /* 4120 * Free up all the allocations related to the name<-->id cache. 4121 * This function should only be called when the nfsuserd daemon isn't 4122 * running, since it doesn't do any locking. 4123 * This function is meant to be used when the nfscommon module is unloaded. 4124 */ 4125 void 4126 nfsrv_cleanusergroup(void) 4127 { 4128 struct nfsrv_lughash *hp, *hp2; 4129 struct nfsusrgrp *nusrp, *usrp; 4130 int i; 4131 4132 if (nfsuserhash == NULL) 4133 return; 4134 4135 for (i = 0; i < nfsrv_lughashsize; i++) { 4136 hp = &nfsuserhash[i]; 4137 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 4138 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4139 hp2 = NFSUSERNAMEHASH(usrp->lug_name, 4140 usrp->lug_namelen); 4141 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 4142 if (usrp->lug_cred != NULL) 4143 crfree(usrp->lug_cred); 4144 free(usrp, M_NFSUSERGROUP); 4145 } 4146 hp = &nfsgrouphash[i]; 4147 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 4148 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4149 hp2 = NFSGROUPNAMEHASH(usrp->lug_name, 4150 usrp->lug_namelen); 4151 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 4152 if (usrp->lug_cred != NULL) 4153 crfree(usrp->lug_cred); 4154 free(usrp, M_NFSUSERGROUP); 4155 } 4156 mtx_destroy(&nfsuserhash[i].mtx); 4157 mtx_destroy(&nfsusernamehash[i].mtx); 4158 mtx_destroy(&nfsgroupnamehash[i].mtx); 4159 mtx_destroy(&nfsgrouphash[i].mtx); 4160 } 4161 free(nfsuserhash, M_NFSUSERGROUP); 4162 free(nfsusernamehash, M_NFSUSERGROUP); 4163 free(nfsgrouphash, M_NFSUSERGROUP); 4164 free(nfsgroupnamehash, M_NFSUSERGROUP); 4165 free(nfsrv_dnsname, M_NFSSTRING); 4166 } 4167 4168 /* 4169 * This function scans a byte string and checks for UTF-8 compliance. 4170 * It returns 0 if it conforms and NFSERR_INVAL if not. 4171 */ 4172 int 4173 nfsrv_checkutf8(u_int8_t *cp, int len) 4174 { 4175 u_int32_t val = 0x0; 4176 int cnt = 0, gotd = 0, shift = 0; 4177 u_int8_t byte; 4178 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 4179 int error = 0; 4180 4181 /* 4182 * Here are what the variables are used for: 4183 * val - the calculated value of a multibyte char, used to check 4184 * that it was coded with the correct range 4185 * cnt - the number of 10xxxxxx bytes to follow 4186 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 4187 * shift - lower order bits of range (ie. "val >> shift" should 4188 * not be 0, in other words, dividing by the lower bound 4189 * of the range should get a non-zero value) 4190 * byte - used to calculate cnt 4191 */ 4192 while (len > 0) { 4193 if (cnt > 0) { 4194 /* This handles the 10xxxxxx bytes */ 4195 if ((*cp & 0xc0) != 0x80 || 4196 (gotd && (*cp & 0x20))) { 4197 error = NFSERR_INVAL; 4198 goto out; 4199 } 4200 gotd = 0; 4201 val <<= 6; 4202 val |= (*cp & 0x3f); 4203 cnt--; 4204 if (cnt == 0 && (val >> shift) == 0x0) { 4205 error = NFSERR_INVAL; 4206 goto out; 4207 } 4208 } else if (*cp & 0x80) { 4209 /* first byte of multi byte char */ 4210 byte = *cp; 4211 while ((byte & 0x40) && cnt < 6) { 4212 cnt++; 4213 byte <<= 1; 4214 } 4215 if (cnt == 0 || cnt == 6) { 4216 error = NFSERR_INVAL; 4217 goto out; 4218 } 4219 val = (*cp & (0x3f >> cnt)); 4220 shift = utf8_shift[cnt - 1]; 4221 if (cnt == 2 && val == 0xd) 4222 /* Check for the 0xd800-0xdfff case */ 4223 gotd = 1; 4224 } 4225 cp++; 4226 len--; 4227 } 4228 if (cnt > 0) 4229 error = NFSERR_INVAL; 4230 4231 out: 4232 NFSEXITCODE(error); 4233 return (error); 4234 } 4235 4236 /* 4237 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 4238 * strings, one with the root path in it and the other with the list of 4239 * locations. The list is in the same format as is found in nfr_refs. 4240 * It is a "," separated list of entries, where each of them is of the 4241 * form <server>:<rootpath>. For example 4242 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 4243 * The nilp argument is set to 1 for the special case of a null fs_root 4244 * and an empty server list. 4245 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 4246 * number of xdr bytes parsed in sump. 4247 */ 4248 static int 4249 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 4250 int *sump, int *nilp) 4251 { 4252 u_int32_t *tl; 4253 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 4254 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 4255 struct list { 4256 SLIST_ENTRY(list) next; 4257 int len; 4258 u_char host[1]; 4259 } *lsp, *nlsp; 4260 SLIST_HEAD(, list) head; 4261 4262 *fsrootp = NULL; 4263 *srvp = NULL; 4264 *nilp = 0; 4265 4266 /* 4267 * Get the fs_root path and check for the special case of null path 4268 * and 0 length server list. 4269 */ 4270 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4271 len = fxdr_unsigned(int, *tl); 4272 if (len < 0 || len > 10240) { 4273 error = NFSERR_BADXDR; 4274 goto nfsmout; 4275 } 4276 if (len == 0) { 4277 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4278 if (*tl != 0) { 4279 error = NFSERR_BADXDR; 4280 goto nfsmout; 4281 } 4282 *nilp = 1; 4283 *sump = 2 * NFSX_UNSIGNED; 4284 error = 0; 4285 goto nfsmout; 4286 } 4287 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 4288 error = nfsrv_mtostr(nd, cp, len); 4289 if (!error) { 4290 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4291 cnt = fxdr_unsigned(int, *tl); 4292 if (cnt <= 0) 4293 error = NFSERR_BADXDR; 4294 } 4295 if (error) 4296 goto nfsmout; 4297 4298 /* 4299 * Now, loop through the location list and make up the srvlist. 4300 */ 4301 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 4302 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 4303 slen = 1024; 4304 siz = 0; 4305 for (i = 0; i < cnt; i++) { 4306 SLIST_INIT(&head); 4307 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4308 nsrv = fxdr_unsigned(int, *tl); 4309 if (nsrv <= 0) { 4310 error = NFSERR_BADXDR; 4311 goto nfsmout; 4312 } 4313 4314 /* 4315 * Handle the first server by putting it in the srvstr. 4316 */ 4317 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4318 len = fxdr_unsigned(int, *tl); 4319 if (len <= 0 || len > 1024) { 4320 error = NFSERR_BADXDR; 4321 goto nfsmout; 4322 } 4323 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 4324 if (cp3 != cp2) { 4325 *cp3++ = ','; 4326 siz++; 4327 } 4328 error = nfsrv_mtostr(nd, cp3, len); 4329 if (error) 4330 goto nfsmout; 4331 cp3 += len; 4332 *cp3++ = ':'; 4333 siz += (len + 1); 4334 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 4335 for (j = 1; j < nsrv; j++) { 4336 /* 4337 * Yuck, put them in an slist and process them later. 4338 */ 4339 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4340 len = fxdr_unsigned(int, *tl); 4341 if (len <= 0 || len > 1024) { 4342 error = NFSERR_BADXDR; 4343 goto nfsmout; 4344 } 4345 lsp = (struct list *)malloc(sizeof (struct list) 4346 + len, M_TEMP, M_WAITOK); 4347 error = nfsrv_mtostr(nd, lsp->host, len); 4348 if (error) 4349 goto nfsmout; 4350 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 4351 lsp->len = len; 4352 SLIST_INSERT_HEAD(&head, lsp, next); 4353 } 4354 4355 /* 4356 * Finally, we can get the path. 4357 */ 4358 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4359 len = fxdr_unsigned(int, *tl); 4360 if (len <= 0 || len > 1024) { 4361 error = NFSERR_BADXDR; 4362 goto nfsmout; 4363 } 4364 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 4365 error = nfsrv_mtostr(nd, cp3, len); 4366 if (error) 4367 goto nfsmout; 4368 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 4369 str = cp3; 4370 stringlen = len; 4371 cp3 += len; 4372 siz += len; 4373 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 4374 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 4375 &cp2, &cp3, &slen); 4376 *cp3++ = ','; 4377 NFSBCOPY(lsp->host, cp3, lsp->len); 4378 cp3 += lsp->len; 4379 *cp3++ = ':'; 4380 NFSBCOPY(str, cp3, stringlen); 4381 cp3 += stringlen; 4382 *cp3 = '\0'; 4383 siz += (lsp->len + stringlen + 2); 4384 free(lsp, M_TEMP); 4385 } 4386 } 4387 *fsrootp = cp; 4388 *srvp = cp2; 4389 *sump = xdrsum; 4390 NFSEXITCODE2(0, nd); 4391 return (0); 4392 nfsmout: 4393 if (cp != NULL) 4394 free(cp, M_NFSSTRING); 4395 if (cp2 != NULL) 4396 free(cp2, M_NFSSTRING); 4397 NFSEXITCODE2(error, nd); 4398 return (error); 4399 } 4400 4401 /* 4402 * Make the malloc'd space large enough. This is a pain, but the xdr 4403 * doesn't set an upper bound on the side, so... 4404 */ 4405 static void 4406 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 4407 { 4408 u_char *cp; 4409 int i; 4410 4411 if (siz <= *slenp) 4412 return; 4413 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 4414 NFSBCOPY(*cpp, cp, *slenp); 4415 free(*cpp, M_NFSSTRING); 4416 i = *cpp2 - *cpp; 4417 *cpp = cp; 4418 *cpp2 = cp + i; 4419 *slenp = siz + 1024; 4420 } 4421 4422 /* 4423 * Initialize the reply header data structures. 4424 */ 4425 void 4426 nfsrvd_rephead(struct nfsrv_descript *nd) 4427 { 4428 struct mbuf *mreq; 4429 4430 if ((nd->nd_flag & ND_EXTPG) != 0) { 4431 mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK); 4432 nd->nd_mreq = nd->nd_mb = mreq; 4433 nd->nd_bpos = (char *)(void *) 4434 PHYS_TO_DMAP(mreq->m_epg_pa[0]); 4435 nd->nd_bextpg = 0; 4436 nd->nd_bextpgsiz = PAGE_SIZE; 4437 } else { 4438 /* 4439 * If this is a big reply, use a cluster. 4440 */ 4441 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 4442 nfs_bigreply[nd->nd_procnum]) { 4443 NFSMCLGET(mreq, M_WAITOK); 4444 nd->nd_mreq = mreq; 4445 nd->nd_mb = mreq; 4446 } else { 4447 NFSMGET(mreq); 4448 nd->nd_mreq = mreq; 4449 nd->nd_mb = mreq; 4450 } 4451 nd->nd_bpos = mtod(mreq, char *); 4452 mreq->m_len = 0; 4453 } 4454 4455 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 4456 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 4457 } 4458 4459 /* 4460 * Lock a socket against others. 4461 * Currently used to serialize connect/disconnect attempts. 4462 */ 4463 int 4464 newnfs_sndlock(int *flagp) 4465 { 4466 struct timespec ts; 4467 4468 NFSLOCKSOCK(); 4469 while (*flagp & NFSR_SNDLOCK) { 4470 *flagp |= NFSR_WANTSND; 4471 ts.tv_sec = 0; 4472 ts.tv_nsec = 0; 4473 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 4474 PZERO - 1, "nfsndlck", &ts); 4475 } 4476 *flagp |= NFSR_SNDLOCK; 4477 NFSUNLOCKSOCK(); 4478 return (0); 4479 } 4480 4481 /* 4482 * Unlock the stream socket for others. 4483 */ 4484 void 4485 newnfs_sndunlock(int *flagp) 4486 { 4487 4488 NFSLOCKSOCK(); 4489 if ((*flagp & NFSR_SNDLOCK) == 0) 4490 panic("nfs sndunlock"); 4491 *flagp &= ~NFSR_SNDLOCK; 4492 if (*flagp & NFSR_WANTSND) { 4493 *flagp &= ~NFSR_WANTSND; 4494 wakeup((caddr_t)flagp); 4495 } 4496 NFSUNLOCKSOCK(); 4497 } 4498 4499 int 4500 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin, 4501 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp) 4502 { 4503 struct in_addr saddr; 4504 uint32_t portnum, *tl; 4505 int i, j, k; 4506 sa_family_t af = AF_UNSPEC; 4507 char addr[64], protocol[5], *cp; 4508 int cantparse = 0, error = 0; 4509 uint16_t portv; 4510 4511 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4512 i = fxdr_unsigned(int, *tl); 4513 if (i >= 3 && i <= 4) { 4514 error = nfsrv_mtostr(nd, protocol, i); 4515 if (error) 4516 goto nfsmout; 4517 if (strcmp(protocol, "tcp") == 0) { 4518 af = AF_INET; 4519 *isudp = 0; 4520 } else if (strcmp(protocol, "udp") == 0) { 4521 af = AF_INET; 4522 *isudp = 1; 4523 } else if (strcmp(protocol, "tcp6") == 0) { 4524 af = AF_INET6; 4525 *isudp = 0; 4526 } else if (strcmp(protocol, "udp6") == 0) { 4527 af = AF_INET6; 4528 *isudp = 1; 4529 } else 4530 cantparse = 1; 4531 } else { 4532 cantparse = 1; 4533 if (i > 0) { 4534 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4535 if (error) 4536 goto nfsmout; 4537 } 4538 } 4539 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4540 i = fxdr_unsigned(int, *tl); 4541 if (i < 0) { 4542 error = NFSERR_BADXDR; 4543 goto nfsmout; 4544 } else if (cantparse == 0 && i >= 11 && i < 64) { 4545 /* 4546 * The shortest address is 11chars and the longest is < 64. 4547 */ 4548 error = nfsrv_mtostr(nd, addr, i); 4549 if (error) 4550 goto nfsmout; 4551 4552 /* Find the port# at the end and extract that. */ 4553 i = strlen(addr); 4554 k = 0; 4555 cp = &addr[i - 1]; 4556 /* Count back two '.'s from end to get port# field. */ 4557 for (j = 0; j < i; j++) { 4558 if (*cp == '.') { 4559 k++; 4560 if (k == 2) 4561 break; 4562 } 4563 cp--; 4564 } 4565 if (k == 2) { 4566 /* 4567 * The NFSv4 port# is appended as .N.N, where N is 4568 * a decimal # in the range 0-255, just like an inet4 4569 * address. Cheat and use inet_aton(), which will 4570 * return a Class A address and then shift the high 4571 * order 8bits over to convert it to the port#. 4572 */ 4573 *cp++ = '\0'; 4574 if (inet_aton(cp, &saddr) == 1) { 4575 portnum = ntohl(saddr.s_addr); 4576 portv = (uint16_t)((portnum >> 16) | 4577 (portnum & 0xff)); 4578 } else 4579 cantparse = 1; 4580 } else 4581 cantparse = 1; 4582 if (cantparse == 0) { 4583 if (af == AF_INET) { 4584 if (inet_pton(af, addr, &sin->sin_addr) == 1) { 4585 sin->sin_len = sizeof(*sin); 4586 sin->sin_family = AF_INET; 4587 sin->sin_port = htons(portv); 4588 *saf = af; 4589 return (0); 4590 } 4591 } else { 4592 if (inet_pton(af, addr, &sin6->sin6_addr) 4593 == 1) { 4594 sin6->sin6_len = sizeof(*sin6); 4595 sin6->sin6_family = AF_INET6; 4596 sin6->sin6_port = htons(portv); 4597 *saf = af; 4598 return (0); 4599 } 4600 } 4601 } 4602 } else { 4603 if (i > 0) { 4604 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4605 if (error) 4606 goto nfsmout; 4607 } 4608 } 4609 error = EPERM; 4610 nfsmout: 4611 return (error); 4612 } 4613 4614 /* 4615 * Handle an NFSv4.1 Sequence request for the session. 4616 * If reply != NULL, use it to return the cached reply, as required. 4617 * The client gets a cached reply via this call for callbacks, however the 4618 * server gets a cached reply via the nfsv4_seqsess_cachereply() call. 4619 */ 4620 int 4621 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 4622 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 4623 { 4624 int error; 4625 4626 error = 0; 4627 if (reply != NULL) 4628 *reply = NULL; 4629 if (slotid > maxslot) 4630 return (NFSERR_BADSLOT); 4631 if (seqid == slots[slotid].nfssl_seq) { 4632 /* A retry. */ 4633 if (slots[slotid].nfssl_inprog != 0) 4634 error = NFSERR_DELAY; 4635 else if (slots[slotid].nfssl_reply != NULL) { 4636 if (reply != NULL) { 4637 *reply = slots[slotid].nfssl_reply; 4638 slots[slotid].nfssl_reply = NULL; 4639 } 4640 slots[slotid].nfssl_inprog = 1; 4641 error = NFSERR_REPLYFROMCACHE; 4642 } else 4643 /* No reply cached, so just do it. */ 4644 slots[slotid].nfssl_inprog = 1; 4645 } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 4646 if (slots[slotid].nfssl_reply != NULL) 4647 m_freem(slots[slotid].nfssl_reply); 4648 slots[slotid].nfssl_reply = NULL; 4649 slots[slotid].nfssl_inprog = 1; 4650 slots[slotid].nfssl_seq++; 4651 } else 4652 error = NFSERR_SEQMISORDERED; 4653 return (error); 4654 } 4655 4656 /* 4657 * Cache this reply for the slot. 4658 * Use the "rep" argument to return the cached reply if repstat is set to 4659 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value. 4660 */ 4661 void 4662 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat, 4663 struct mbuf **rep) 4664 { 4665 4666 if (repstat == NFSERR_REPLYFROMCACHE) { 4667 *rep = slots[slotid].nfssl_reply; 4668 slots[slotid].nfssl_reply = NULL; 4669 } else { 4670 if (slots[slotid].nfssl_reply != NULL) 4671 m_freem(slots[slotid].nfssl_reply); 4672 slots[slotid].nfssl_reply = *rep; 4673 } 4674 slots[slotid].nfssl_inprog = 0; 4675 } 4676 4677 /* 4678 * Generate the xdr for an NFSv4.1 Sequence Operation. 4679 */ 4680 void 4681 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, 4682 struct nfsclsession *sep, int dont_replycache) 4683 { 4684 uint32_t *tl, slotseq = 0; 4685 int error, maxslot, slotpos; 4686 uint8_t sessionid[NFSX_V4SESSIONID]; 4687 4688 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq, 4689 sessionid); 4690 nd->nd_maxreq = sep->nfsess_maxreq; 4691 nd->nd_maxresp = sep->nfsess_maxresp; 4692 4693 /* Build the Sequence arguments. */ 4694 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 4695 nd->nd_sequence = tl; 4696 bcopy(sessionid, tl, NFSX_V4SESSIONID); 4697 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4698 nd->nd_slotseq = tl; 4699 if (error == 0) { 4700 nd->nd_flag |= ND_HASSLOTID; 4701 nd->nd_slotid = slotpos; 4702 *tl++ = txdr_unsigned(slotseq); 4703 *tl++ = txdr_unsigned(slotpos); 4704 *tl++ = txdr_unsigned(maxslot); 4705 if (dont_replycache == 0) 4706 *tl = newnfs_true; 4707 else 4708 *tl = newnfs_false; 4709 } else { 4710 /* 4711 * There are two errors and the rest of the session can 4712 * just be zeros. 4713 * NFSERR_BADSESSION: This bad session should just generate 4714 * the same error again when the RPC is retried. 4715 * ESTALE: A forced dismount is in progress and will cause the 4716 * RPC to fail later. 4717 */ 4718 *tl++ = 0; 4719 *tl++ = 0; 4720 *tl++ = 0; 4721 *tl = 0; 4722 } 4723 nd->nd_flag |= ND_HASSEQUENCE; 4724 } 4725 4726 int 4727 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep, 4728 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid) 4729 { 4730 int i, maxslot, slotpos; 4731 uint64_t bitval; 4732 4733 /* Find an unused slot. */ 4734 slotpos = -1; 4735 maxslot = -1; 4736 mtx_lock(&sep->nfsess_mtx); 4737 do { 4738 if (nmp != NULL && sep->nfsess_defunct != 0) { 4739 /* Just return the bad session. */ 4740 bcopy(sep->nfsess_sessionid, sessionid, 4741 NFSX_V4SESSIONID); 4742 mtx_unlock(&sep->nfsess_mtx); 4743 return (NFSERR_BADSESSION); 4744 } 4745 bitval = 1; 4746 for (i = 0; i < sep->nfsess_foreslots; i++) { 4747 if ((bitval & sep->nfsess_slots) == 0) { 4748 slotpos = i; 4749 sep->nfsess_slots |= bitval; 4750 sep->nfsess_slotseq[i]++; 4751 *slotseqp = sep->nfsess_slotseq[i]; 4752 break; 4753 } 4754 bitval <<= 1; 4755 } 4756 if (slotpos == -1) { 4757 /* 4758 * If a forced dismount is in progress, just return. 4759 * This RPC attempt will fail when it calls 4760 * newnfs_request(). 4761 */ 4762 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) { 4763 mtx_unlock(&sep->nfsess_mtx); 4764 return (ESTALE); 4765 } 4766 /* Wake up once/sec, to check for a forced dismount. */ 4767 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 4768 PZERO, "nfsclseq", hz); 4769 } 4770 } while (slotpos == -1); 4771 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 4772 bitval = 1; 4773 for (i = 0; i < 64; i++) { 4774 if ((bitval & sep->nfsess_slots) != 0) 4775 maxslot = i; 4776 bitval <<= 1; 4777 } 4778 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 4779 mtx_unlock(&sep->nfsess_mtx); 4780 *slotposp = slotpos; 4781 *maxslotp = maxslot; 4782 return (0); 4783 } 4784 4785 /* 4786 * Free a session slot. 4787 */ 4788 void 4789 nfsv4_freeslot(struct nfsclsession *sep, int slot) 4790 { 4791 uint64_t bitval; 4792 4793 bitval = 1; 4794 if (slot > 0) 4795 bitval <<= slot; 4796 mtx_lock(&sep->nfsess_mtx); 4797 if ((bitval & sep->nfsess_slots) == 0) 4798 printf("freeing free slot!!\n"); 4799 sep->nfsess_slots &= ~bitval; 4800 wakeup(&sep->nfsess_slots); 4801 mtx_unlock(&sep->nfsess_mtx); 4802 } 4803 4804 /* 4805 * Search for a matching pnfsd DS, based on the nmp arg. 4806 * Return one if found, NULL otherwise. 4807 */ 4808 struct nfsdevice * 4809 nfsv4_findmirror(struct nfsmount *nmp) 4810 { 4811 struct nfsdevice *ds; 4812 4813 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED); 4814 /* 4815 * Search the DS server list for a match with nmp. 4816 */ 4817 if (nfsrv_devidcnt == 0) 4818 return (NULL); 4819 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) { 4820 if (ds->nfsdev_nmp == nmp) { 4821 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n"); 4822 break; 4823 } 4824 } 4825 return (ds); 4826 } 4827 4828 /* 4829 * Fill in the fields of "struct nfsrv_descript". 4830 */ 4831 void 4832 nfsm_set(struct nfsrv_descript *nd, u_int offs) 4833 { 4834 struct mbuf *m; 4835 int rlen; 4836 4837 m = nd->nd_mb; 4838 if ((m->m_flags & M_EXTPG) != 0) { 4839 nd->nd_bextpg = 0; 4840 while (offs > 0) { 4841 if (nd->nd_bextpg == 0) 4842 rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off); 4843 else 4844 rlen = m_epg_pagelen(m, nd->nd_bextpg, 0); 4845 if (offs <= rlen) 4846 break; 4847 offs -= rlen; 4848 nd->nd_bextpg++; 4849 if (nd->nd_bextpg == m->m_epg_npgs) { 4850 printf("nfsm_set: build offs " 4851 "out of range\n"); 4852 nd->nd_bextpg--; 4853 break; 4854 } 4855 } 4856 nd->nd_bpos = (char *)(void *) 4857 PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]); 4858 if (nd->nd_bextpg == 0) 4859 nd->nd_bpos += m->m_epg_1st_off; 4860 if (offs > 0) { 4861 nd->nd_bpos += offs; 4862 nd->nd_bextpgsiz = rlen - offs; 4863 } else if (nd->nd_bextpg == 0) 4864 nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off; 4865 else 4866 nd->nd_bextpgsiz = PAGE_SIZE; 4867 } else 4868 nd->nd_bpos = mtod(m, char *) + offs; 4869 } 4870 4871 /* 4872 * Grow a ext_pgs mbuf list. Either allocate another page or add 4873 * an mbuf to the list. 4874 */ 4875 struct mbuf * 4876 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg) 4877 { 4878 struct mbuf *mp; 4879 vm_page_t pg; 4880 4881 if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) { 4882 mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK); 4883 *bextpg = 0; 4884 m->m_next = mp; 4885 } else { 4886 do { 4887 pg = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | 4888 VM_ALLOC_NOOBJ | VM_ALLOC_NODUMP | 4889 VM_ALLOC_WIRED); 4890 if (pg == NULL) 4891 vm_wait(NULL); 4892 } while (pg == NULL); 4893 m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg); 4894 *bextpg = m->m_epg_npgs; 4895 m->m_epg_npgs++; 4896 m->m_epg_last_len = 0; 4897 mp = m; 4898 } 4899 return (mp); 4900 } 4901