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