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