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