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