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(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 goto out; 3518 } 3519 nfsrv_nfsuserd = 1; 3520 NFSUNLOCKNAMEID(); 3521 /* 3522 * Set up the socket record and connect. 3523 */ 3524 rp = &nfsrv_nfsuserdsock; 3525 rp->nr_client = NULL; 3526 rp->nr_sotype = SOCK_DGRAM; 3527 rp->nr_soproto = IPPROTO_UDP; 3528 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 3529 rp->nr_cred = NULL; 3530 rp->nr_nam = malloc(sizeof(*rp->nr_nam), M_SONAME, M_WAITOK | M_ZERO); 3531 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in)); 3532 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *); 3533 ad->sin_family = AF_INET; 3534 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */ 3535 ad->sin_port = port; 3536 rp->nr_prog = RPCPROG_NFSUSERD; 3537 rp->nr_vers = RPCNFSUSERD_VERS; 3538 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 3539 if (error) { 3540 free(rp->nr_nam, M_SONAME); 3541 nfsrv_nfsuserd = 0; 3542 } 3543 out: 3544 NFSEXITCODE(error); 3545 return (error); 3546 } 3547 3548 /* 3549 * Delete the nfsuserd port. 3550 */ 3551 APPLESTATIC void 3552 nfsrv_nfsuserddelport(void) 3553 { 3554 3555 NFSLOCKNAMEID(); 3556 if (nfsrv_nfsuserd == 0) { 3557 NFSUNLOCKNAMEID(); 3558 return; 3559 } 3560 nfsrv_nfsuserd = 0; 3561 NFSUNLOCKNAMEID(); 3562 newnfs_disconnect(&nfsrv_nfsuserdsock); 3563 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME); 3564 } 3565 3566 /* 3567 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 3568 * name<-->id cache. 3569 * Returns 0 upon success, non-zero otherwise. 3570 */ 3571 static int 3572 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name) 3573 { 3574 u_int32_t *tl; 3575 struct nfsrv_descript *nd; 3576 int len; 3577 struct nfsrv_descript nfsd; 3578 struct ucred *cred; 3579 int error; 3580 3581 NFSLOCKNAMEID(); 3582 if (nfsrv_nfsuserd == 0) { 3583 NFSUNLOCKNAMEID(); 3584 error = EPERM; 3585 goto out; 3586 } 3587 NFSUNLOCKNAMEID(); 3588 nd = &nfsd; 3589 cred = newnfs_getcred(); 3590 nd->nd_flag = ND_GSSINITREPLY; 3591 nfsrvd_rephead(nd); 3592 3593 nd->nd_procnum = procnum; 3594 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3595 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3596 if (procnum == RPCNFSUSERD_GETUID) 3597 *tl = txdr_unsigned(uid); 3598 else 3599 *tl = txdr_unsigned(gid); 3600 } else { 3601 len = strlen(name); 3602 (void) nfsm_strtom(nd, name, len); 3603 } 3604 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 3605 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL); 3606 NFSFREECRED(cred); 3607 if (!error) { 3608 mbuf_freem(nd->nd_mrep); 3609 error = nd->nd_repstat; 3610 } 3611 out: 3612 NFSEXITCODE(error); 3613 return (error); 3614 } 3615 3616 /* 3617 * This function is called from the nfssvc(2) system call, to update the 3618 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3619 */ 3620 APPLESTATIC int 3621 nfssvc_idname(struct nfsd_idargs *nidp) 3622 { 3623 struct nfsusrgrp *nusrp, *usrp, *newusrp; 3624 struct nfsrv_lughash *hp_name, *hp_idnum, *thp; 3625 int i, group_locked, groupname_locked, user_locked, username_locked; 3626 int error = 0; 3627 u_char *cp; 3628 gid_t *grps; 3629 struct ucred *cr; 3630 static int onethread = 0; 3631 static time_t lasttime = 0; 3632 3633 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) { 3634 error = EINVAL; 3635 goto out; 3636 } 3637 if (nidp->nid_flag & NFSID_INITIALIZE) { 3638 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); 3639 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 3640 nidp->nid_namelen); 3641 if (error != 0) { 3642 free(cp, M_NFSSTRING); 3643 goto out; 3644 } 3645 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) { 3646 /* 3647 * Free up all the old stuff and reinitialize hash 3648 * lists. All mutexes for both lists must be locked, 3649 * with the user/group name ones before the uid/gid 3650 * ones, to avoid a LOR. 3651 */ 3652 for (i = 0; i < nfsrv_lughashsize; i++) 3653 mtx_lock(&nfsusernamehash[i].mtx); 3654 for (i = 0; i < nfsrv_lughashsize; i++) 3655 mtx_lock(&nfsuserhash[i].mtx); 3656 for (i = 0; i < nfsrv_lughashsize; i++) 3657 TAILQ_FOREACH_SAFE(usrp, 3658 &nfsuserhash[i].lughead, lug_numhash, nusrp) 3659 nfsrv_removeuser(usrp, 1); 3660 for (i = 0; i < nfsrv_lughashsize; i++) 3661 mtx_unlock(&nfsuserhash[i].mtx); 3662 for (i = 0; i < nfsrv_lughashsize; i++) 3663 mtx_unlock(&nfsusernamehash[i].mtx); 3664 for (i = 0; i < nfsrv_lughashsize; i++) 3665 mtx_lock(&nfsgroupnamehash[i].mtx); 3666 for (i = 0; i < nfsrv_lughashsize; i++) 3667 mtx_lock(&nfsgrouphash[i].mtx); 3668 for (i = 0; i < nfsrv_lughashsize; i++) 3669 TAILQ_FOREACH_SAFE(usrp, 3670 &nfsgrouphash[i].lughead, lug_numhash, 3671 nusrp) 3672 nfsrv_removeuser(usrp, 0); 3673 for (i = 0; i < nfsrv_lughashsize; i++) 3674 mtx_unlock(&nfsgrouphash[i].mtx); 3675 for (i = 0; i < nfsrv_lughashsize; i++) 3676 mtx_unlock(&nfsgroupnamehash[i].mtx); 3677 free(nfsrv_dnsname, M_NFSSTRING); 3678 nfsrv_dnsname = NULL; 3679 } 3680 if (nfsuserhash == NULL) { 3681 /* Allocate the hash tables. */ 3682 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) * 3683 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3684 M_ZERO); 3685 for (i = 0; i < nfsrv_lughashsize; i++) 3686 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash", 3687 NULL, MTX_DEF | MTX_DUPOK); 3688 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) * 3689 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3690 M_ZERO); 3691 for (i = 0; i < nfsrv_lughashsize; i++) 3692 mtx_init(&nfsusernamehash[i].mtx, 3693 "nfsusrhash", NULL, MTX_DEF | 3694 MTX_DUPOK); 3695 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) * 3696 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3697 M_ZERO); 3698 for (i = 0; i < nfsrv_lughashsize; i++) 3699 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash", 3700 NULL, MTX_DEF | MTX_DUPOK); 3701 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) * 3702 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3703 M_ZERO); 3704 for (i = 0; i < nfsrv_lughashsize; i++) 3705 mtx_init(&nfsgroupnamehash[i].mtx, 3706 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK); 3707 } 3708 /* (Re)initialize the list heads. */ 3709 for (i = 0; i < nfsrv_lughashsize; i++) 3710 TAILQ_INIT(&nfsuserhash[i].lughead); 3711 for (i = 0; i < nfsrv_lughashsize; i++) 3712 TAILQ_INIT(&nfsusernamehash[i].lughead); 3713 for (i = 0; i < nfsrv_lughashsize; i++) 3714 TAILQ_INIT(&nfsgrouphash[i].lughead); 3715 for (i = 0; i < nfsrv_lughashsize; i++) 3716 TAILQ_INIT(&nfsgroupnamehash[i].lughead); 3717 3718 /* 3719 * Put name in "DNS" string. 3720 */ 3721 nfsrv_dnsname = cp; 3722 nfsrv_defaultuid = nidp->nid_uid; 3723 nfsrv_defaultgid = nidp->nid_gid; 3724 nfsrv_usercnt = 0; 3725 nfsrv_usermax = nidp->nid_usermax; 3726 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen); 3727 goto out; 3728 } 3729 3730 /* 3731 * malloc the new one now, so any potential sleep occurs before 3732 * manipulation of the lists. 3733 */ 3734 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, 3735 M_NFSUSERGROUP, M_WAITOK | M_ZERO); 3736 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 3737 nidp->nid_namelen); 3738 if (error == 0 && nidp->nid_ngroup > 0 && 3739 (nidp->nid_flag & NFSID_ADDUID) != 0) { 3740 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP, 3741 M_WAITOK); 3742 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps, 3743 sizeof(gid_t) * nidp->nid_ngroup); 3744 if (error == 0) { 3745 /* 3746 * Create a credential just like svc_getcred(), 3747 * but using the group list provided. 3748 */ 3749 cr = crget(); 3750 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; 3751 crsetgroups(cr, nidp->nid_ngroup, grps); 3752 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; 3753 cr->cr_prison = &prison0; 3754 prison_hold(cr->cr_prison); 3755 #ifdef MAC 3756 mac_cred_associate_nfsd(cr); 3757 #endif 3758 newusrp->lug_cred = cr; 3759 } 3760 free(grps, M_TEMP); 3761 } 3762 if (error) { 3763 free(newusrp, M_NFSUSERGROUP); 3764 goto out; 3765 } 3766 newusrp->lug_namelen = nidp->nid_namelen; 3767 3768 /* 3769 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed 3770 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group. 3771 * The flags user_locked, username_locked, group_locked and 3772 * groupname_locked are set to indicate all of those hash lists are 3773 * locked. hp_name != NULL and hp_idnum != NULL indicates that 3774 * the respective one mutex is locked. 3775 */ 3776 user_locked = username_locked = group_locked = groupname_locked = 0; 3777 hp_name = hp_idnum = NULL; 3778 3779 /* 3780 * Delete old entries, as required. 3781 */ 3782 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3783 /* Must lock all username hash lists first, to avoid a LOR. */ 3784 for (i = 0; i < nfsrv_lughashsize; i++) 3785 mtx_lock(&nfsusernamehash[i].mtx); 3786 username_locked = 1; 3787 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3788 mtx_lock(&hp_idnum->mtx); 3789 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3790 nusrp) { 3791 if (usrp->lug_uid == nidp->nid_uid) 3792 nfsrv_removeuser(usrp, 1); 3793 } 3794 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3795 hp_name = NFSUSERNAMEHASH(newusrp->lug_name, 3796 newusrp->lug_namelen); 3797 mtx_lock(&hp_name->mtx); 3798 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3799 nusrp) { 3800 if (usrp->lug_namelen == newusrp->lug_namelen && 3801 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3802 usrp->lug_namelen)) { 3803 thp = NFSUSERHASH(usrp->lug_uid); 3804 mtx_lock(&thp->mtx); 3805 nfsrv_removeuser(usrp, 1); 3806 mtx_unlock(&thp->mtx); 3807 } 3808 } 3809 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3810 mtx_lock(&hp_idnum->mtx); 3811 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3812 /* Must lock all groupname hash lists first, to avoid a LOR. */ 3813 for (i = 0; i < nfsrv_lughashsize; i++) 3814 mtx_lock(&nfsgroupnamehash[i].mtx); 3815 groupname_locked = 1; 3816 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3817 mtx_lock(&hp_idnum->mtx); 3818 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3819 nusrp) { 3820 if (usrp->lug_gid == nidp->nid_gid) 3821 nfsrv_removeuser(usrp, 0); 3822 } 3823 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3824 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name, 3825 newusrp->lug_namelen); 3826 mtx_lock(&hp_name->mtx); 3827 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3828 nusrp) { 3829 if (usrp->lug_namelen == newusrp->lug_namelen && 3830 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3831 usrp->lug_namelen)) { 3832 thp = NFSGROUPHASH(usrp->lug_gid); 3833 mtx_lock(&thp->mtx); 3834 nfsrv_removeuser(usrp, 0); 3835 mtx_unlock(&thp->mtx); 3836 } 3837 } 3838 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3839 mtx_lock(&hp_idnum->mtx); 3840 } 3841 3842 /* 3843 * Now, we can add the new one. 3844 */ 3845 if (nidp->nid_usertimeout) 3846 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3847 else 3848 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3849 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3850 newusrp->lug_uid = nidp->nid_uid; 3851 thp = NFSUSERHASH(newusrp->lug_uid); 3852 mtx_assert(&thp->mtx, MA_OWNED); 3853 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3854 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3855 mtx_assert(&thp->mtx, MA_OWNED); 3856 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3857 atomic_add_int(&nfsrv_usercnt, 1); 3858 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3859 newusrp->lug_gid = nidp->nid_gid; 3860 thp = NFSGROUPHASH(newusrp->lug_gid); 3861 mtx_assert(&thp->mtx, MA_OWNED); 3862 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3863 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3864 mtx_assert(&thp->mtx, MA_OWNED); 3865 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3866 atomic_add_int(&nfsrv_usercnt, 1); 3867 } else { 3868 if (newusrp->lug_cred != NULL) 3869 crfree(newusrp->lug_cred); 3870 free(newusrp, M_NFSUSERGROUP); 3871 } 3872 3873 /* 3874 * Once per second, allow one thread to trim the cache. 3875 */ 3876 if (lasttime < NFSD_MONOSEC && 3877 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) { 3878 /* 3879 * First, unlock the single mutexes, so that all entries 3880 * can be locked and any LOR is avoided. 3881 */ 3882 if (hp_name != NULL) { 3883 mtx_unlock(&hp_name->mtx); 3884 hp_name = NULL; 3885 } 3886 if (hp_idnum != NULL) { 3887 mtx_unlock(&hp_idnum->mtx); 3888 hp_idnum = NULL; 3889 } 3890 3891 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID | 3892 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) { 3893 if (username_locked == 0) { 3894 for (i = 0; i < nfsrv_lughashsize; i++) 3895 mtx_lock(&nfsusernamehash[i].mtx); 3896 username_locked = 1; 3897 } 3898 KASSERT(user_locked == 0, 3899 ("nfssvc_idname: user_locked")); 3900 for (i = 0; i < nfsrv_lughashsize; i++) 3901 mtx_lock(&nfsuserhash[i].mtx); 3902 user_locked = 1; 3903 for (i = 0; i < nfsrv_lughashsize; i++) { 3904 TAILQ_FOREACH_SAFE(usrp, 3905 &nfsuserhash[i].lughead, lug_numhash, 3906 nusrp) 3907 if (usrp->lug_expiry < NFSD_MONOSEC) 3908 nfsrv_removeuser(usrp, 1); 3909 } 3910 for (i = 0; i < nfsrv_lughashsize; i++) { 3911 /* 3912 * Trim the cache using an approximate LRU 3913 * algorithm. This code deletes the least 3914 * recently used entry on each hash list. 3915 */ 3916 if (nfsrv_usercnt <= nfsrv_usermax) 3917 break; 3918 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead); 3919 if (usrp != NULL) 3920 nfsrv_removeuser(usrp, 1); 3921 } 3922 } else { 3923 if (groupname_locked == 0) { 3924 for (i = 0; i < nfsrv_lughashsize; i++) 3925 mtx_lock(&nfsgroupnamehash[i].mtx); 3926 groupname_locked = 1; 3927 } 3928 KASSERT(group_locked == 0, 3929 ("nfssvc_idname: group_locked")); 3930 for (i = 0; i < nfsrv_lughashsize; i++) 3931 mtx_lock(&nfsgrouphash[i].mtx); 3932 group_locked = 1; 3933 for (i = 0; i < nfsrv_lughashsize; i++) { 3934 TAILQ_FOREACH_SAFE(usrp, 3935 &nfsgrouphash[i].lughead, lug_numhash, 3936 nusrp) 3937 if (usrp->lug_expiry < NFSD_MONOSEC) 3938 nfsrv_removeuser(usrp, 0); 3939 } 3940 for (i = 0; i < nfsrv_lughashsize; i++) { 3941 /* 3942 * Trim the cache using an approximate LRU 3943 * algorithm. This code deletes the least 3944 * recently user entry on each hash list. 3945 */ 3946 if (nfsrv_usercnt <= nfsrv_usermax) 3947 break; 3948 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead); 3949 if (usrp != NULL) 3950 nfsrv_removeuser(usrp, 0); 3951 } 3952 } 3953 lasttime = NFSD_MONOSEC; 3954 atomic_store_rel_int(&onethread, 0); 3955 } 3956 3957 /* Now, unlock all locked mutexes. */ 3958 if (hp_idnum != NULL) 3959 mtx_unlock(&hp_idnum->mtx); 3960 if (hp_name != NULL) 3961 mtx_unlock(&hp_name->mtx); 3962 if (user_locked != 0) 3963 for (i = 0; i < nfsrv_lughashsize; i++) 3964 mtx_unlock(&nfsuserhash[i].mtx); 3965 if (username_locked != 0) 3966 for (i = 0; i < nfsrv_lughashsize; i++) 3967 mtx_unlock(&nfsusernamehash[i].mtx); 3968 if (group_locked != 0) 3969 for (i = 0; i < nfsrv_lughashsize; i++) 3970 mtx_unlock(&nfsgrouphash[i].mtx); 3971 if (groupname_locked != 0) 3972 for (i = 0; i < nfsrv_lughashsize; i++) 3973 mtx_unlock(&nfsgroupnamehash[i].mtx); 3974 out: 3975 NFSEXITCODE(error); 3976 return (error); 3977 } 3978 3979 /* 3980 * Remove a user/group name element. 3981 */ 3982 static void 3983 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser) 3984 { 3985 struct nfsrv_lughash *hp; 3986 3987 if (isuser != 0) { 3988 hp = NFSUSERHASH(usrp->lug_uid); 3989 mtx_assert(&hp->mtx, MA_OWNED); 3990 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3991 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3992 mtx_assert(&hp->mtx, MA_OWNED); 3993 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 3994 } else { 3995 hp = NFSGROUPHASH(usrp->lug_gid); 3996 mtx_assert(&hp->mtx, MA_OWNED); 3997 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3998 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3999 mtx_assert(&hp->mtx, MA_OWNED); 4000 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 4001 } 4002 atomic_add_int(&nfsrv_usercnt, -1); 4003 if (usrp->lug_cred != NULL) 4004 crfree(usrp->lug_cred); 4005 free(usrp, M_NFSUSERGROUP); 4006 } 4007 4008 /* 4009 * Free up all the allocations related to the name<-->id cache. 4010 * This function should only be called when the nfsuserd daemon isn't 4011 * running, since it doesn't do any locking. 4012 * This function is meant to be used when the nfscommon module is unloaded. 4013 */ 4014 APPLESTATIC void 4015 nfsrv_cleanusergroup(void) 4016 { 4017 struct nfsrv_lughash *hp, *hp2; 4018 struct nfsusrgrp *nusrp, *usrp; 4019 int i; 4020 4021 if (nfsuserhash == NULL) 4022 return; 4023 4024 for (i = 0; i < nfsrv_lughashsize; i++) { 4025 hp = &nfsuserhash[i]; 4026 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 4027 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4028 hp2 = NFSUSERNAMEHASH(usrp->lug_name, 4029 usrp->lug_namelen); 4030 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 4031 if (usrp->lug_cred != NULL) 4032 crfree(usrp->lug_cred); 4033 free(usrp, M_NFSUSERGROUP); 4034 } 4035 hp = &nfsgrouphash[i]; 4036 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 4037 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4038 hp2 = NFSGROUPNAMEHASH(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 mtx_destroy(&nfsuserhash[i].mtx); 4046 mtx_destroy(&nfsusernamehash[i].mtx); 4047 mtx_destroy(&nfsgroupnamehash[i].mtx); 4048 mtx_destroy(&nfsgrouphash[i].mtx); 4049 } 4050 free(nfsuserhash, M_NFSUSERGROUP); 4051 free(nfsusernamehash, M_NFSUSERGROUP); 4052 free(nfsgrouphash, M_NFSUSERGROUP); 4053 free(nfsgroupnamehash, M_NFSUSERGROUP); 4054 free(nfsrv_dnsname, M_NFSSTRING); 4055 } 4056 4057 /* 4058 * This function scans a byte string and checks for UTF-8 compliance. 4059 * It returns 0 if it conforms and NFSERR_INVAL if not. 4060 */ 4061 APPLESTATIC int 4062 nfsrv_checkutf8(u_int8_t *cp, int len) 4063 { 4064 u_int32_t val = 0x0; 4065 int cnt = 0, gotd = 0, shift = 0; 4066 u_int8_t byte; 4067 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 4068 int error = 0; 4069 4070 /* 4071 * Here are what the variables are used for: 4072 * val - the calculated value of a multibyte char, used to check 4073 * that it was coded with the correct range 4074 * cnt - the number of 10xxxxxx bytes to follow 4075 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 4076 * shift - lower order bits of range (ie. "val >> shift" should 4077 * not be 0, in other words, dividing by the lower bound 4078 * of the range should get a non-zero value) 4079 * byte - used to calculate cnt 4080 */ 4081 while (len > 0) { 4082 if (cnt > 0) { 4083 /* This handles the 10xxxxxx bytes */ 4084 if ((*cp & 0xc0) != 0x80 || 4085 (gotd && (*cp & 0x20))) { 4086 error = NFSERR_INVAL; 4087 goto out; 4088 } 4089 gotd = 0; 4090 val <<= 6; 4091 val |= (*cp & 0x3f); 4092 cnt--; 4093 if (cnt == 0 && (val >> shift) == 0x0) { 4094 error = NFSERR_INVAL; 4095 goto out; 4096 } 4097 } else if (*cp & 0x80) { 4098 /* first byte of multi byte char */ 4099 byte = *cp; 4100 while ((byte & 0x40) && cnt < 6) { 4101 cnt++; 4102 byte <<= 1; 4103 } 4104 if (cnt == 0 || cnt == 6) { 4105 error = NFSERR_INVAL; 4106 goto out; 4107 } 4108 val = (*cp & (0x3f >> cnt)); 4109 shift = utf8_shift[cnt - 1]; 4110 if (cnt == 2 && val == 0xd) 4111 /* Check for the 0xd800-0xdfff case */ 4112 gotd = 1; 4113 } 4114 cp++; 4115 len--; 4116 } 4117 if (cnt > 0) 4118 error = NFSERR_INVAL; 4119 4120 out: 4121 NFSEXITCODE(error); 4122 return (error); 4123 } 4124 4125 /* 4126 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 4127 * strings, one with the root path in it and the other with the list of 4128 * locations. The list is in the same format as is found in nfr_refs. 4129 * It is a "," separated list of entries, where each of them is of the 4130 * form <server>:<rootpath>. For example 4131 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 4132 * The nilp argument is set to 1 for the special case of a null fs_root 4133 * and an empty server list. 4134 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 4135 * number of xdr bytes parsed in sump. 4136 */ 4137 static int 4138 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 4139 int *sump, int *nilp) 4140 { 4141 u_int32_t *tl; 4142 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 4143 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 4144 struct list { 4145 SLIST_ENTRY(list) next; 4146 int len; 4147 u_char host[1]; 4148 } *lsp, *nlsp; 4149 SLIST_HEAD(, list) head; 4150 4151 *fsrootp = NULL; 4152 *srvp = NULL; 4153 *nilp = 0; 4154 4155 /* 4156 * Get the fs_root path and check for the special case of null path 4157 * and 0 length server list. 4158 */ 4159 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4160 len = fxdr_unsigned(int, *tl); 4161 if (len < 0 || len > 10240) { 4162 error = NFSERR_BADXDR; 4163 goto nfsmout; 4164 } 4165 if (len == 0) { 4166 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4167 if (*tl != 0) { 4168 error = NFSERR_BADXDR; 4169 goto nfsmout; 4170 } 4171 *nilp = 1; 4172 *sump = 2 * NFSX_UNSIGNED; 4173 error = 0; 4174 goto nfsmout; 4175 } 4176 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 4177 error = nfsrv_mtostr(nd, cp, len); 4178 if (!error) { 4179 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4180 cnt = fxdr_unsigned(int, *tl); 4181 if (cnt <= 0) 4182 error = NFSERR_BADXDR; 4183 } 4184 if (error) 4185 goto nfsmout; 4186 4187 /* 4188 * Now, loop through the location list and make up the srvlist. 4189 */ 4190 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 4191 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 4192 slen = 1024; 4193 siz = 0; 4194 for (i = 0; i < cnt; i++) { 4195 SLIST_INIT(&head); 4196 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4197 nsrv = fxdr_unsigned(int, *tl); 4198 if (nsrv <= 0) { 4199 error = NFSERR_BADXDR; 4200 goto nfsmout; 4201 } 4202 4203 /* 4204 * Handle the first server by putting it in the srvstr. 4205 */ 4206 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4207 len = fxdr_unsigned(int, *tl); 4208 if (len <= 0 || len > 1024) { 4209 error = NFSERR_BADXDR; 4210 goto nfsmout; 4211 } 4212 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 4213 if (cp3 != cp2) { 4214 *cp3++ = ','; 4215 siz++; 4216 } 4217 error = nfsrv_mtostr(nd, cp3, len); 4218 if (error) 4219 goto nfsmout; 4220 cp3 += len; 4221 *cp3++ = ':'; 4222 siz += (len + 1); 4223 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 4224 for (j = 1; j < nsrv; j++) { 4225 /* 4226 * Yuck, put them in an slist and process them later. 4227 */ 4228 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4229 len = fxdr_unsigned(int, *tl); 4230 if (len <= 0 || len > 1024) { 4231 error = NFSERR_BADXDR; 4232 goto nfsmout; 4233 } 4234 lsp = (struct list *)malloc(sizeof (struct list) 4235 + len, M_TEMP, M_WAITOK); 4236 error = nfsrv_mtostr(nd, lsp->host, len); 4237 if (error) 4238 goto nfsmout; 4239 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 4240 lsp->len = len; 4241 SLIST_INSERT_HEAD(&head, lsp, next); 4242 } 4243 4244 /* 4245 * Finally, we can get the path. 4246 */ 4247 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4248 len = fxdr_unsigned(int, *tl); 4249 if (len <= 0 || len > 1024) { 4250 error = NFSERR_BADXDR; 4251 goto nfsmout; 4252 } 4253 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 4254 error = nfsrv_mtostr(nd, cp3, len); 4255 if (error) 4256 goto nfsmout; 4257 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 4258 str = cp3; 4259 stringlen = len; 4260 cp3 += len; 4261 siz += len; 4262 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 4263 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 4264 &cp2, &cp3, &slen); 4265 *cp3++ = ','; 4266 NFSBCOPY(lsp->host, cp3, lsp->len); 4267 cp3 += lsp->len; 4268 *cp3++ = ':'; 4269 NFSBCOPY(str, cp3, stringlen); 4270 cp3 += stringlen; 4271 *cp3 = '\0'; 4272 siz += (lsp->len + stringlen + 2); 4273 free(lsp, M_TEMP); 4274 } 4275 } 4276 *fsrootp = cp; 4277 *srvp = cp2; 4278 *sump = xdrsum; 4279 NFSEXITCODE2(0, nd); 4280 return (0); 4281 nfsmout: 4282 if (cp != NULL) 4283 free(cp, M_NFSSTRING); 4284 if (cp2 != NULL) 4285 free(cp2, M_NFSSTRING); 4286 NFSEXITCODE2(error, nd); 4287 return (error); 4288 } 4289 4290 /* 4291 * Make the malloc'd space large enough. This is a pain, but the xdr 4292 * doesn't set an upper bound on the side, so... 4293 */ 4294 static void 4295 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 4296 { 4297 u_char *cp; 4298 int i; 4299 4300 if (siz <= *slenp) 4301 return; 4302 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 4303 NFSBCOPY(*cpp, cp, *slenp); 4304 free(*cpp, M_NFSSTRING); 4305 i = *cpp2 - *cpp; 4306 *cpp = cp; 4307 *cpp2 = cp + i; 4308 *slenp = siz + 1024; 4309 } 4310 4311 /* 4312 * Initialize the reply header data structures. 4313 */ 4314 APPLESTATIC void 4315 nfsrvd_rephead(struct nfsrv_descript *nd) 4316 { 4317 mbuf_t mreq; 4318 4319 /* 4320 * If this is a big reply, use a cluster. 4321 */ 4322 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 4323 nfs_bigreply[nd->nd_procnum]) { 4324 NFSMCLGET(mreq, M_WAITOK); 4325 nd->nd_mreq = mreq; 4326 nd->nd_mb = mreq; 4327 } else { 4328 NFSMGET(mreq); 4329 nd->nd_mreq = mreq; 4330 nd->nd_mb = mreq; 4331 } 4332 nd->nd_bpos = NFSMTOD(mreq, caddr_t); 4333 mbuf_setlen(mreq, 0); 4334 4335 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 4336 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 4337 } 4338 4339 /* 4340 * Lock a socket against others. 4341 * Currently used to serialize connect/disconnect attempts. 4342 */ 4343 int 4344 newnfs_sndlock(int *flagp) 4345 { 4346 struct timespec ts; 4347 4348 NFSLOCKSOCK(); 4349 while (*flagp & NFSR_SNDLOCK) { 4350 *flagp |= NFSR_WANTSND; 4351 ts.tv_sec = 0; 4352 ts.tv_nsec = 0; 4353 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 4354 PZERO - 1, "nfsndlck", &ts); 4355 } 4356 *flagp |= NFSR_SNDLOCK; 4357 NFSUNLOCKSOCK(); 4358 return (0); 4359 } 4360 4361 /* 4362 * Unlock the stream socket for others. 4363 */ 4364 void 4365 newnfs_sndunlock(int *flagp) 4366 { 4367 4368 NFSLOCKSOCK(); 4369 if ((*flagp & NFSR_SNDLOCK) == 0) 4370 panic("nfs sndunlock"); 4371 *flagp &= ~NFSR_SNDLOCK; 4372 if (*flagp & NFSR_WANTSND) { 4373 *flagp &= ~NFSR_WANTSND; 4374 wakeup((caddr_t)flagp); 4375 } 4376 NFSUNLOCKSOCK(); 4377 } 4378 4379 APPLESTATIC int 4380 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin, 4381 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp) 4382 { 4383 struct in_addr saddr; 4384 uint32_t portnum, *tl; 4385 int i, j, k; 4386 sa_family_t af = AF_UNSPEC; 4387 char addr[64], protocol[5], *cp; 4388 int cantparse = 0, error = 0; 4389 uint16_t portv; 4390 4391 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4392 i = fxdr_unsigned(int, *tl); 4393 if (i >= 3 && i <= 4) { 4394 error = nfsrv_mtostr(nd, protocol, i); 4395 if (error) 4396 goto nfsmout; 4397 if (strcmp(protocol, "tcp") == 0) { 4398 af = AF_INET; 4399 *isudp = 0; 4400 } else if (strcmp(protocol, "udp") == 0) { 4401 af = AF_INET; 4402 *isudp = 1; 4403 } else if (strcmp(protocol, "tcp6") == 0) { 4404 af = AF_INET6; 4405 *isudp = 0; 4406 } else if (strcmp(protocol, "udp6") == 0) { 4407 af = AF_INET6; 4408 *isudp = 1; 4409 } else 4410 cantparse = 1; 4411 } else { 4412 cantparse = 1; 4413 if (i > 0) { 4414 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4415 if (error) 4416 goto nfsmout; 4417 } 4418 } 4419 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4420 i = fxdr_unsigned(int, *tl); 4421 if (i < 0) { 4422 error = NFSERR_BADXDR; 4423 goto nfsmout; 4424 } else if (cantparse == 0 && i >= 11 && i < 64) { 4425 /* 4426 * The shortest address is 11chars and the longest is < 64. 4427 */ 4428 error = nfsrv_mtostr(nd, addr, i); 4429 if (error) 4430 goto nfsmout; 4431 4432 /* Find the port# at the end and extract that. */ 4433 i = strlen(addr); 4434 k = 0; 4435 cp = &addr[i - 1]; 4436 /* Count back two '.'s from end to get port# field. */ 4437 for (j = 0; j < i; j++) { 4438 if (*cp == '.') { 4439 k++; 4440 if (k == 2) 4441 break; 4442 } 4443 cp--; 4444 } 4445 if (k == 2) { 4446 /* 4447 * The NFSv4 port# is appended as .N.N, where N is 4448 * a decimal # in the range 0-255, just like an inet4 4449 * address. Cheat and use inet_aton(), which will 4450 * return a Class A address and then shift the high 4451 * order 8bits over to convert it to the port#. 4452 */ 4453 *cp++ = '\0'; 4454 if (inet_aton(cp, &saddr) == 1) { 4455 portnum = ntohl(saddr.s_addr); 4456 portv = (uint16_t)((portnum >> 16) | 4457 (portnum & 0xff)); 4458 } else 4459 cantparse = 1; 4460 } else 4461 cantparse = 1; 4462 if (cantparse == 0) { 4463 if (af == AF_INET) { 4464 if (inet_pton(af, addr, &sin->sin_addr) == 1) { 4465 sin->sin_len = sizeof(*sin); 4466 sin->sin_family = AF_INET; 4467 sin->sin_port = htons(portv); 4468 *saf = af; 4469 return (0); 4470 } 4471 } else { 4472 if (inet_pton(af, addr, &sin6->sin6_addr) 4473 == 1) { 4474 sin6->sin6_len = sizeof(*sin6); 4475 sin6->sin6_family = AF_INET6; 4476 sin6->sin6_port = htons(portv); 4477 *saf = af; 4478 return (0); 4479 } 4480 } 4481 } 4482 } else { 4483 if (i > 0) { 4484 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4485 if (error) 4486 goto nfsmout; 4487 } 4488 } 4489 error = EPERM; 4490 nfsmout: 4491 return (error); 4492 } 4493 4494 /* 4495 * Handle an NFSv4.1 Sequence request for the session. 4496 * If reply != NULL, use it to return the cached reply, as required. 4497 * The client gets a cached reply via this call for callbacks, however the 4498 * server gets a cached reply via the nfsv4_seqsess_cachereply() call. 4499 */ 4500 int 4501 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 4502 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 4503 { 4504 int error; 4505 4506 error = 0; 4507 if (reply != NULL) 4508 *reply = NULL; 4509 if (slotid > maxslot) 4510 return (NFSERR_BADSLOT); 4511 if (seqid == slots[slotid].nfssl_seq) { 4512 /* A retry. */ 4513 if (slots[slotid].nfssl_inprog != 0) 4514 error = NFSERR_DELAY; 4515 else if (slots[slotid].nfssl_reply != NULL) { 4516 if (reply != NULL) { 4517 *reply = slots[slotid].nfssl_reply; 4518 slots[slotid].nfssl_reply = NULL; 4519 } 4520 slots[slotid].nfssl_inprog = 1; 4521 error = NFSERR_REPLYFROMCACHE; 4522 } else 4523 /* No reply cached, so just do it. */ 4524 slots[slotid].nfssl_inprog = 1; 4525 } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 4526 if (slots[slotid].nfssl_reply != NULL) 4527 m_freem(slots[slotid].nfssl_reply); 4528 slots[slotid].nfssl_reply = NULL; 4529 slots[slotid].nfssl_inprog = 1; 4530 slots[slotid].nfssl_seq++; 4531 } else 4532 error = NFSERR_SEQMISORDERED; 4533 return (error); 4534 } 4535 4536 /* 4537 * Cache this reply for the slot. 4538 * Use the "rep" argument to return the cached reply if repstat is set to 4539 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value. 4540 */ 4541 void 4542 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat, 4543 struct mbuf **rep) 4544 { 4545 4546 if (repstat == NFSERR_REPLYFROMCACHE) { 4547 *rep = slots[slotid].nfssl_reply; 4548 slots[slotid].nfssl_reply = NULL; 4549 } else { 4550 if (slots[slotid].nfssl_reply != NULL) 4551 m_freem(slots[slotid].nfssl_reply); 4552 slots[slotid].nfssl_reply = *rep; 4553 } 4554 slots[slotid].nfssl_inprog = 0; 4555 } 4556 4557 /* 4558 * Generate the xdr for an NFSv4.1 Sequence Operation. 4559 */ 4560 APPLESTATIC void 4561 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, 4562 struct nfsclsession *sep, int dont_replycache) 4563 { 4564 uint32_t *tl, slotseq = 0; 4565 int error, maxslot, slotpos; 4566 uint8_t sessionid[NFSX_V4SESSIONID]; 4567 4568 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq, 4569 sessionid); 4570 4571 /* Build the Sequence arguments. */ 4572 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 4573 nd->nd_sequence = tl; 4574 bcopy(sessionid, tl, NFSX_V4SESSIONID); 4575 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4576 nd->nd_slotseq = tl; 4577 if (error == 0) { 4578 nd->nd_flag |= ND_HASSLOTID; 4579 nd->nd_slotid = slotpos; 4580 *tl++ = txdr_unsigned(slotseq); 4581 *tl++ = txdr_unsigned(slotpos); 4582 *tl++ = txdr_unsigned(maxslot); 4583 if (dont_replycache == 0) 4584 *tl = newnfs_true; 4585 else 4586 *tl = newnfs_false; 4587 } else { 4588 /* 4589 * There are two errors and the rest of the session can 4590 * just be zeros. 4591 * NFSERR_BADSESSION: This bad session should just generate 4592 * the same error again when the RPC is retried. 4593 * ESTALE: A forced dismount is in progress and will cause the 4594 * RPC to fail later. 4595 */ 4596 *tl++ = 0; 4597 *tl++ = 0; 4598 *tl++ = 0; 4599 *tl = 0; 4600 } 4601 nd->nd_flag |= ND_HASSEQUENCE; 4602 } 4603 4604 int 4605 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep, 4606 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid) 4607 { 4608 int i, maxslot, slotpos; 4609 uint64_t bitval; 4610 4611 /* Find an unused slot. */ 4612 slotpos = -1; 4613 maxslot = -1; 4614 mtx_lock(&sep->nfsess_mtx); 4615 do { 4616 if (nmp != NULL && sep->nfsess_defunct != 0) { 4617 /* Just return the bad session. */ 4618 bcopy(sep->nfsess_sessionid, sessionid, 4619 NFSX_V4SESSIONID); 4620 mtx_unlock(&sep->nfsess_mtx); 4621 return (NFSERR_BADSESSION); 4622 } 4623 bitval = 1; 4624 for (i = 0; i < sep->nfsess_foreslots; i++) { 4625 if ((bitval & sep->nfsess_slots) == 0) { 4626 slotpos = i; 4627 sep->nfsess_slots |= bitval; 4628 sep->nfsess_slotseq[i]++; 4629 *slotseqp = sep->nfsess_slotseq[i]; 4630 break; 4631 } 4632 bitval <<= 1; 4633 } 4634 if (slotpos == -1) { 4635 /* 4636 * If a forced dismount is in progress, just return. 4637 * This RPC attempt will fail when it calls 4638 * newnfs_request(). 4639 */ 4640 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) { 4641 mtx_unlock(&sep->nfsess_mtx); 4642 return (ESTALE); 4643 } 4644 /* Wake up once/sec, to check for a forced dismount. */ 4645 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 4646 PZERO, "nfsclseq", hz); 4647 } 4648 } while (slotpos == -1); 4649 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 4650 bitval = 1; 4651 for (i = 0; i < 64; i++) { 4652 if ((bitval & sep->nfsess_slots) != 0) 4653 maxslot = i; 4654 bitval <<= 1; 4655 } 4656 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 4657 mtx_unlock(&sep->nfsess_mtx); 4658 *slotposp = slotpos; 4659 *maxslotp = maxslot; 4660 return (0); 4661 } 4662 4663 /* 4664 * Free a session slot. 4665 */ 4666 APPLESTATIC void 4667 nfsv4_freeslot(struct nfsclsession *sep, int slot) 4668 { 4669 uint64_t bitval; 4670 4671 bitval = 1; 4672 if (slot > 0) 4673 bitval <<= slot; 4674 mtx_lock(&sep->nfsess_mtx); 4675 if ((bitval & sep->nfsess_slots) == 0) 4676 printf("freeing free slot!!\n"); 4677 sep->nfsess_slots &= ~bitval; 4678 wakeup(&sep->nfsess_slots); 4679 mtx_unlock(&sep->nfsess_mtx); 4680 } 4681 4682 /* 4683 * Search for a matching pnfsd DS, based on the nmp arg. 4684 * Return one if found, NULL otherwise. 4685 */ 4686 struct nfsdevice * 4687 nfsv4_findmirror(struct nfsmount *nmp) 4688 { 4689 struct nfsdevice *ds; 4690 4691 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED); 4692 /* 4693 * Search the DS server list for a match with nmp. 4694 */ 4695 if (nfsrv_devidcnt == 0) 4696 return (NULL); 4697 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) { 4698 if (ds->nfsdev_nmp == nmp) { 4699 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n"); 4700 break; 4701 } 4702 } 4703 return (ds); 4704 } 4705 4706