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