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