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