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