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