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