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