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