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