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