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