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