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