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