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 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] || 1406 thyp2 != (u_int64_t) 1407 vfs_statfs(vnode_mount(vp))->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(vnode_mount(vp),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(vnode_mount(vp),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(vnode_mount(vp),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_TIMEMODIFYSET: 2926 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2927 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2928 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2929 txdr_nfsv4time(&vap->va_mtime, tl); 2930 retnum += NFSX_V4SETTIME; 2931 } else { 2932 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2933 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2934 retnum += NFSX_UNSIGNED; 2935 } 2936 break; 2937 case NFSATTRBIT_MOUNTEDONFILEID: 2938 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2939 if (at_root != 0) 2940 uquad = mounted_on_fileno; 2941 else 2942 uquad = vap->va_fileid; 2943 txdr_hyper(uquad, tl); 2944 retnum += NFSX_HYPER; 2945 break; 2946 case NFSATTRBIT_SUPPATTREXCLCREAT: 2947 NFSSETSUPP_ATTRBIT(&attrbits, nd); 2948 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd); 2949 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); 2950 retnum += nfsrv_putattrbit(nd, &attrbits); 2951 break; 2952 case NFSATTRBIT_FSLAYOUTTYPE: 2953 case NFSATTRBIT_LAYOUTTYPE: 2954 if (nfsrv_devidcnt == 0) 2955 siz = 1; 2956 else 2957 siz = 2; 2958 if (siz == 2) { 2959 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2960 *tl++ = txdr_unsigned(1); /* One entry. */ 2961 if (nfsrv_doflexfile != 0 || 2962 nfsrv_maxpnfsmirror > 1) 2963 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE); 2964 else 2965 *tl = txdr_unsigned( 2966 NFSLAYOUT_NFSV4_1_FILES); 2967 } else { 2968 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2969 *tl = 0; 2970 } 2971 retnum += siz * NFSX_UNSIGNED; 2972 break; 2973 case NFSATTRBIT_LAYOUTALIGNMENT: 2974 case NFSATTRBIT_LAYOUTBLKSIZE: 2975 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2976 *tl = txdr_unsigned(NFS_SRVMAXIO); 2977 retnum += NFSX_UNSIGNED; 2978 break; 2979 case NFSATTRBIT_XATTRSUPPORT: 2980 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2981 if (xattrsupp) 2982 *tl = newnfs_true; 2983 else 2984 *tl = newnfs_false; 2985 retnum += NFSX_UNSIGNED; 2986 break; 2987 default: 2988 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2989 } 2990 } 2991 } 2992 if (naclp != NULL) 2993 acl_free(naclp); 2994 free(fs, M_STATFS); 2995 *retnump = txdr_unsigned(retnum); 2996 return (retnum + prefixnum); 2997 } 2998 2999 /* 3000 * Put the attribute bits onto an mbuf list. 3001 * Return the number of bytes of output generated. 3002 */ 3003 int 3004 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 3005 { 3006 u_int32_t *tl; 3007 int cnt, i, bytesize; 3008 3009 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 3010 if (attrbitp->bits[cnt - 1]) 3011 break; 3012 bytesize = (cnt + 1) * NFSX_UNSIGNED; 3013 NFSM_BUILD(tl, u_int32_t *, bytesize); 3014 *tl++ = txdr_unsigned(cnt); 3015 for (i = 0; i < cnt; i++) 3016 *tl++ = txdr_unsigned(attrbitp->bits[i]); 3017 return (bytesize); 3018 } 3019 3020 /* 3021 * Convert a uid to a string. 3022 * If the lookup fails, just output the digits. 3023 * uid - the user id 3024 * cpp - points to a buffer of size NFSV4_SMALLSTR 3025 * (malloc a larger one, as required) 3026 * retlenp - pointer to length to be returned 3027 */ 3028 void 3029 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp) 3030 { 3031 int i; 3032 struct nfsusrgrp *usrp; 3033 u_char *cp = *cpp; 3034 uid_t tmp; 3035 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 3036 struct nfsrv_lughash *hp; 3037 3038 cnt = 0; 3039 tryagain: 3040 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) { 3041 /* 3042 * Always map nfsrv_defaultuid to "nobody". 3043 */ 3044 if (uid == nfsrv_defaultuid) { 3045 i = nfsrv_dnsnamelen + 7; 3046 if (i > len) { 3047 if (len > NFSV4_SMALLSTR) 3048 free(cp, M_NFSSTRING); 3049 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3050 *cpp = cp; 3051 len = i; 3052 goto tryagain; 3053 } 3054 *retlenp = i; 3055 NFSBCOPY("nobody@", cp, 7); 3056 cp += 7; 3057 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 3058 return; 3059 } 3060 hasampersand = 0; 3061 hp = NFSUSERHASH(uid); 3062 mtx_lock(&hp->mtx); 3063 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 3064 if (usrp->lug_uid == uid) { 3065 if (usrp->lug_expiry < NFSD_MONOSEC) 3066 break; 3067 /* 3068 * If the name doesn't already have an '@' 3069 * in it, append @domainname to it. 3070 */ 3071 for (i = 0; i < usrp->lug_namelen; i++) { 3072 if (usrp->lug_name[i] == '@') { 3073 hasampersand = 1; 3074 break; 3075 } 3076 } 3077 if (hasampersand) 3078 i = usrp->lug_namelen; 3079 else 3080 i = usrp->lug_namelen + 3081 nfsrv_dnsnamelen + 1; 3082 if (i > len) { 3083 mtx_unlock(&hp->mtx); 3084 if (len > NFSV4_SMALLSTR) 3085 free(cp, M_NFSSTRING); 3086 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3087 *cpp = cp; 3088 len = i; 3089 goto tryagain; 3090 } 3091 *retlenp = i; 3092 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 3093 if (!hasampersand) { 3094 cp += usrp->lug_namelen; 3095 *cp++ = '@'; 3096 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 3097 } 3098 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3099 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 3100 lug_numhash); 3101 mtx_unlock(&hp->mtx); 3102 return; 3103 } 3104 } 3105 mtx_unlock(&hp->mtx); 3106 cnt++; 3107 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL); 3108 if (ret == 0 && cnt < 2) 3109 goto tryagain; 3110 } 3111 3112 /* 3113 * No match, just return a string of digits. 3114 */ 3115 tmp = uid; 3116 i = 0; 3117 while (tmp || i == 0) { 3118 tmp /= 10; 3119 i++; 3120 } 3121 len = (i > len) ? len : i; 3122 *retlenp = len; 3123 cp += (len - 1); 3124 tmp = uid; 3125 for (i = 0; i < len; i++) { 3126 *cp-- = '0' + (tmp % 10); 3127 tmp /= 10; 3128 } 3129 return; 3130 } 3131 3132 /* 3133 * Get a credential for the uid with the server's group list. 3134 * If none is found, just return the credential passed in after 3135 * logging a warning message. 3136 */ 3137 struct ucred * 3138 nfsrv_getgrpscred(struct ucred *oldcred) 3139 { 3140 struct nfsusrgrp *usrp; 3141 struct ucred *newcred; 3142 int cnt, ret; 3143 uid_t uid; 3144 struct nfsrv_lughash *hp; 3145 3146 cnt = 0; 3147 uid = oldcred->cr_uid; 3148 tryagain: 3149 if (nfsrv_dnsnamelen > 0) { 3150 hp = NFSUSERHASH(uid); 3151 mtx_lock(&hp->mtx); 3152 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 3153 if (usrp->lug_uid == uid) { 3154 if (usrp->lug_expiry < NFSD_MONOSEC) 3155 break; 3156 if (usrp->lug_cred != NULL) { 3157 newcred = crhold(usrp->lug_cred); 3158 crfree(oldcred); 3159 } else 3160 newcred = oldcred; 3161 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3162 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 3163 lug_numhash); 3164 mtx_unlock(&hp->mtx); 3165 return (newcred); 3166 } 3167 } 3168 mtx_unlock(&hp->mtx); 3169 cnt++; 3170 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL); 3171 if (ret == 0 && cnt < 2) 3172 goto tryagain; 3173 } 3174 return (oldcred); 3175 } 3176 3177 /* 3178 * Convert a string to a uid. 3179 * If no conversion is possible return NFSERR_BADOWNER, otherwise 3180 * return 0. 3181 * If this is called from a client side mount using AUTH_SYS and the 3182 * string is made up entirely of digits, just convert the string to 3183 * a number. 3184 */ 3185 int 3186 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp) 3187 { 3188 int i; 3189 char *cp, *endstr, *str0; 3190 struct nfsusrgrp *usrp; 3191 int cnt, ret; 3192 int error = 0; 3193 uid_t tuid; 3194 struct nfsrv_lughash *hp, *hp2; 3195 3196 if (len == 0) { 3197 error = NFSERR_BADOWNER; 3198 goto out; 3199 } 3200 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 3201 str0 = str; 3202 tuid = (uid_t)strtoul(str0, &endstr, 10); 3203 if ((endstr - str0) == len) { 3204 /* A numeric string. */ 3205 if ((nd->nd_flag & ND_KERBV) == 0 && 3206 ((nd->nd_flag & ND_NFSCL) != 0 || 3207 nfsd_enable_stringtouid != 0)) 3208 *uidp = tuid; 3209 else 3210 error = NFSERR_BADOWNER; 3211 goto out; 3212 } 3213 /* 3214 * Look for an '@'. 3215 */ 3216 cp = strchr(str0, '@'); 3217 if (cp != NULL) 3218 i = (int)(cp++ - str0); 3219 else 3220 i = len; 3221 3222 cnt = 0; 3223 tryagain: 3224 if (nfsrv_dnsnamelen > 0) { 3225 /* 3226 * If an '@' is found and the domain name matches, search for 3227 * the name with dns stripped off. 3228 * Mixed case alpahbetics will match for the domain name, but 3229 * all upper case will not. 3230 */ 3231 if (cnt == 0 && i < len && i > 0 && 3232 (len - 1 - i) == nfsrv_dnsnamelen && 3233 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 3234 len -= (nfsrv_dnsnamelen + 1); 3235 *(cp - 1) = '\0'; 3236 } 3237 3238 /* 3239 * Check for the special case of "nobody". 3240 */ 3241 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 3242 *uidp = nfsrv_defaultuid; 3243 error = 0; 3244 goto out; 3245 } 3246 3247 hp = NFSUSERNAMEHASH(str, len); 3248 mtx_lock(&hp->mtx); 3249 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 3250 if (usrp->lug_namelen == len && 3251 !NFSBCMP(usrp->lug_name, str, len)) { 3252 if (usrp->lug_expiry < NFSD_MONOSEC) 3253 break; 3254 hp2 = NFSUSERHASH(usrp->lug_uid); 3255 mtx_lock(&hp2->mtx); 3256 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 3257 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 3258 lug_numhash); 3259 *uidp = usrp->lug_uid; 3260 mtx_unlock(&hp2->mtx); 3261 mtx_unlock(&hp->mtx); 3262 error = 0; 3263 goto out; 3264 } 3265 } 3266 mtx_unlock(&hp->mtx); 3267 cnt++; 3268 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 3269 str); 3270 if (ret == 0 && cnt < 2) 3271 goto tryagain; 3272 } 3273 error = NFSERR_BADOWNER; 3274 3275 out: 3276 NFSEXITCODE(error); 3277 return (error); 3278 } 3279 3280 /* 3281 * Convert a gid to a string. 3282 * gid - the group id 3283 * cpp - points to a buffer of size NFSV4_SMALLSTR 3284 * (malloc a larger one, as required) 3285 * retlenp - pointer to length to be returned 3286 */ 3287 void 3288 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp) 3289 { 3290 int i; 3291 struct nfsusrgrp *usrp; 3292 u_char *cp = *cpp; 3293 gid_t tmp; 3294 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 3295 struct nfsrv_lughash *hp; 3296 3297 cnt = 0; 3298 tryagain: 3299 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) { 3300 /* 3301 * Always map nfsrv_defaultgid to "nogroup". 3302 */ 3303 if (gid == nfsrv_defaultgid) { 3304 i = nfsrv_dnsnamelen + 8; 3305 if (i > len) { 3306 if (len > NFSV4_SMALLSTR) 3307 free(cp, M_NFSSTRING); 3308 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3309 *cpp = cp; 3310 len = i; 3311 goto tryagain; 3312 } 3313 *retlenp = i; 3314 NFSBCOPY("nogroup@", cp, 8); 3315 cp += 8; 3316 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 3317 return; 3318 } 3319 hasampersand = 0; 3320 hp = NFSGROUPHASH(gid); 3321 mtx_lock(&hp->mtx); 3322 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 3323 if (usrp->lug_gid == gid) { 3324 if (usrp->lug_expiry < NFSD_MONOSEC) 3325 break; 3326 /* 3327 * If the name doesn't already have an '@' 3328 * in it, append @domainname to it. 3329 */ 3330 for (i = 0; i < usrp->lug_namelen; i++) { 3331 if (usrp->lug_name[i] == '@') { 3332 hasampersand = 1; 3333 break; 3334 } 3335 } 3336 if (hasampersand) 3337 i = usrp->lug_namelen; 3338 else 3339 i = usrp->lug_namelen + 3340 nfsrv_dnsnamelen + 1; 3341 if (i > len) { 3342 mtx_unlock(&hp->mtx); 3343 if (len > NFSV4_SMALLSTR) 3344 free(cp, M_NFSSTRING); 3345 cp = malloc(i, M_NFSSTRING, M_WAITOK); 3346 *cpp = cp; 3347 len = i; 3348 goto tryagain; 3349 } 3350 *retlenp = i; 3351 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 3352 if (!hasampersand) { 3353 cp += usrp->lug_namelen; 3354 *cp++ = '@'; 3355 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 3356 } 3357 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3358 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 3359 lug_numhash); 3360 mtx_unlock(&hp->mtx); 3361 return; 3362 } 3363 } 3364 mtx_unlock(&hp->mtx); 3365 cnt++; 3366 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL); 3367 if (ret == 0 && cnt < 2) 3368 goto tryagain; 3369 } 3370 3371 /* 3372 * No match, just return a string of digits. 3373 */ 3374 tmp = gid; 3375 i = 0; 3376 while (tmp || i == 0) { 3377 tmp /= 10; 3378 i++; 3379 } 3380 len = (i > len) ? len : i; 3381 *retlenp = len; 3382 cp += (len - 1); 3383 tmp = gid; 3384 for (i = 0; i < len; i++) { 3385 *cp-- = '0' + (tmp % 10); 3386 tmp /= 10; 3387 } 3388 return; 3389 } 3390 3391 /* 3392 * Convert a string to a gid. 3393 * If no conversion is possible return NFSERR_BADOWNER, otherwise 3394 * return 0. 3395 * If this is called from a client side mount using AUTH_SYS and the 3396 * string is made up entirely of digits, just convert the string to 3397 * a number. 3398 */ 3399 int 3400 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp) 3401 { 3402 int i; 3403 char *cp, *endstr, *str0; 3404 struct nfsusrgrp *usrp; 3405 int cnt, ret; 3406 int error = 0; 3407 gid_t tgid; 3408 struct nfsrv_lughash *hp, *hp2; 3409 3410 if (len == 0) { 3411 error = NFSERR_BADOWNER; 3412 goto out; 3413 } 3414 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 3415 str0 = str; 3416 tgid = (gid_t)strtoul(str0, &endstr, 10); 3417 if ((endstr - str0) == len) { 3418 /* A numeric string. */ 3419 if ((nd->nd_flag & ND_KERBV) == 0 && 3420 ((nd->nd_flag & ND_NFSCL) != 0 || 3421 nfsd_enable_stringtouid != 0)) 3422 *gidp = tgid; 3423 else 3424 error = NFSERR_BADOWNER; 3425 goto out; 3426 } 3427 /* 3428 * Look for an '@'. 3429 */ 3430 cp = strchr(str0, '@'); 3431 if (cp != NULL) 3432 i = (int)(cp++ - str0); 3433 else 3434 i = len; 3435 3436 cnt = 0; 3437 tryagain: 3438 if (nfsrv_dnsnamelen > 0) { 3439 /* 3440 * If an '@' is found and the dns name matches, search for the 3441 * name with the dns stripped off. 3442 */ 3443 if (cnt == 0 && i < len && i > 0 && 3444 (len - 1 - i) == nfsrv_dnsnamelen && 3445 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 3446 len -= (nfsrv_dnsnamelen + 1); 3447 *(cp - 1) = '\0'; 3448 } 3449 3450 /* 3451 * Check for the special case of "nogroup". 3452 */ 3453 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 3454 *gidp = nfsrv_defaultgid; 3455 error = 0; 3456 goto out; 3457 } 3458 3459 hp = NFSGROUPNAMEHASH(str, len); 3460 mtx_lock(&hp->mtx); 3461 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 3462 if (usrp->lug_namelen == len && 3463 !NFSBCMP(usrp->lug_name, str, len)) { 3464 if (usrp->lug_expiry < NFSD_MONOSEC) 3465 break; 3466 hp2 = NFSGROUPHASH(usrp->lug_gid); 3467 mtx_lock(&hp2->mtx); 3468 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 3469 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 3470 lug_numhash); 3471 *gidp = usrp->lug_gid; 3472 mtx_unlock(&hp2->mtx); 3473 mtx_unlock(&hp->mtx); 3474 error = 0; 3475 goto out; 3476 } 3477 } 3478 mtx_unlock(&hp->mtx); 3479 cnt++; 3480 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 3481 str); 3482 if (ret == 0 && cnt < 2) 3483 goto tryagain; 3484 } 3485 error = NFSERR_BADOWNER; 3486 3487 out: 3488 NFSEXITCODE(error); 3489 return (error); 3490 } 3491 3492 /* 3493 * Cmp len chars, allowing mixed case in the first argument to match lower 3494 * case in the second, but not if the first argument is all upper case. 3495 * Return 0 for a match, 1 otherwise. 3496 */ 3497 static int 3498 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 3499 { 3500 int i; 3501 u_char tmp; 3502 int fndlower = 0; 3503 3504 for (i = 0; i < len; i++) { 3505 if (*cp >= 'A' && *cp <= 'Z') { 3506 tmp = *cp++ + ('a' - 'A'); 3507 } else { 3508 tmp = *cp++; 3509 if (tmp >= 'a' && tmp <= 'z') 3510 fndlower = 1; 3511 } 3512 if (tmp != *cp2++) 3513 return (1); 3514 } 3515 if (fndlower) 3516 return (0); 3517 else 3518 return (1); 3519 } 3520 3521 /* 3522 * Set the port for the nfsuserd. 3523 */ 3524 int 3525 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p) 3526 { 3527 struct nfssockreq *rp; 3528 #ifdef INET 3529 struct sockaddr_in *ad; 3530 #endif 3531 #ifdef INET6 3532 struct sockaddr_in6 *ad6; 3533 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT; 3534 #endif 3535 int error; 3536 3537 NFSLOCKNAMEID(); 3538 if (nfsrv_nfsuserd != NOTRUNNING) { 3539 NFSUNLOCKNAMEID(); 3540 error = EPERM; 3541 goto out; 3542 } 3543 nfsrv_nfsuserd = STARTSTOP; 3544 /* 3545 * Set up the socket record and connect. 3546 * Set nr_client NULL before unlocking, just to ensure that no other 3547 * process/thread/core will use a bogus old value. This could only 3548 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is 3549 * broken. 3550 */ 3551 rp = &nfsrv_nfsuserdsock; 3552 rp->nr_client = NULL; 3553 NFSUNLOCKNAMEID(); 3554 rp->nr_sotype = SOCK_DGRAM; 3555 rp->nr_soproto = IPPROTO_UDP; 3556 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 3557 rp->nr_cred = NULL; 3558 rp->nr_prog = RPCPROG_NFSUSERD; 3559 error = 0; 3560 switch (nargs->nuserd_family) { 3561 #ifdef INET 3562 case AF_INET: 3563 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME, 3564 M_WAITOK | M_ZERO); 3565 ad = (struct sockaddr_in *)rp->nr_nam; 3566 ad->sin_len = sizeof(struct sockaddr_in); 3567 ad->sin_family = AF_INET; 3568 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 3569 ad->sin_port = nargs->nuserd_port; 3570 break; 3571 #endif 3572 #ifdef INET6 3573 case AF_INET6: 3574 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 3575 M_WAITOK | M_ZERO); 3576 ad6 = (struct sockaddr_in6 *)rp->nr_nam; 3577 ad6->sin6_len = sizeof(struct sockaddr_in6); 3578 ad6->sin6_family = AF_INET6; 3579 ad6->sin6_addr = in6loopback; 3580 ad6->sin6_port = nargs->nuserd_port; 3581 break; 3582 #endif 3583 default: 3584 error = ENXIO; 3585 } 3586 rp->nr_vers = RPCNFSUSERD_VERS; 3587 if (error == 0) 3588 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 3589 if (error == 0) { 3590 NFSLOCKNAMEID(); 3591 nfsrv_nfsuserd = RUNNING; 3592 NFSUNLOCKNAMEID(); 3593 } else { 3594 free(rp->nr_nam, M_SONAME); 3595 NFSLOCKNAMEID(); 3596 nfsrv_nfsuserd = NOTRUNNING; 3597 NFSUNLOCKNAMEID(); 3598 } 3599 out: 3600 NFSEXITCODE(error); 3601 return (error); 3602 } 3603 3604 /* 3605 * Delete the nfsuserd port. 3606 */ 3607 void 3608 nfsrv_nfsuserddelport(void) 3609 { 3610 3611 NFSLOCKNAMEID(); 3612 if (nfsrv_nfsuserd != RUNNING) { 3613 NFSUNLOCKNAMEID(); 3614 return; 3615 } 3616 nfsrv_nfsuserd = STARTSTOP; 3617 /* Wait for all upcalls to complete. */ 3618 while (nfsrv_userdupcalls > 0) 3619 msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS, 3620 "nfsupcalls", 0); 3621 NFSUNLOCKNAMEID(); 3622 newnfs_disconnect(&nfsrv_nfsuserdsock); 3623 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME); 3624 NFSLOCKNAMEID(); 3625 nfsrv_nfsuserd = NOTRUNNING; 3626 NFSUNLOCKNAMEID(); 3627 } 3628 3629 /* 3630 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 3631 * name<-->id cache. 3632 * Returns 0 upon success, non-zero otherwise. 3633 */ 3634 static int 3635 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name) 3636 { 3637 u_int32_t *tl; 3638 struct nfsrv_descript *nd; 3639 int len; 3640 struct nfsrv_descript nfsd; 3641 struct ucred *cred; 3642 int error; 3643 3644 NFSLOCKNAMEID(); 3645 if (nfsrv_nfsuserd != RUNNING) { 3646 NFSUNLOCKNAMEID(); 3647 error = EPERM; 3648 goto out; 3649 } 3650 /* 3651 * Maintain a count of upcalls in progress, so that nfsrv_X() 3652 * can wait until no upcalls are in progress. 3653 */ 3654 nfsrv_userdupcalls++; 3655 NFSUNLOCKNAMEID(); 3656 KASSERT(nfsrv_userdupcalls > 0, 3657 ("nfsrv_getuser: non-positive upcalls")); 3658 nd = &nfsd; 3659 cred = newnfs_getcred(); 3660 nd->nd_flag = ND_GSSINITREPLY; 3661 nfsrvd_rephead(nd); 3662 3663 nd->nd_procnum = procnum; 3664 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3665 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3666 if (procnum == RPCNFSUSERD_GETUID) 3667 *tl = txdr_unsigned(uid); 3668 else 3669 *tl = txdr_unsigned(gid); 3670 } else { 3671 len = strlen(name); 3672 (void) nfsm_strtom(nd, name, len); 3673 } 3674 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 3675 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL); 3676 NFSLOCKNAMEID(); 3677 if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP) 3678 wakeup(&nfsrv_userdupcalls); 3679 NFSUNLOCKNAMEID(); 3680 NFSFREECRED(cred); 3681 if (!error) { 3682 m_freem(nd->nd_mrep); 3683 error = nd->nd_repstat; 3684 } 3685 out: 3686 NFSEXITCODE(error); 3687 return (error); 3688 } 3689 3690 /* 3691 * This function is called from the nfssvc(2) system call, to update the 3692 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3693 */ 3694 int 3695 nfssvc_idname(struct nfsd_idargs *nidp) 3696 { 3697 struct nfsusrgrp *nusrp, *usrp, *newusrp; 3698 struct nfsrv_lughash *hp_name, *hp_idnum, *thp; 3699 int i, group_locked, groupname_locked, user_locked, username_locked; 3700 int error = 0; 3701 u_char *cp; 3702 gid_t *grps; 3703 struct ucred *cr; 3704 static int onethread = 0; 3705 static time_t lasttime = 0; 3706 3707 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) { 3708 error = EINVAL; 3709 goto out; 3710 } 3711 if (nidp->nid_flag & NFSID_INITIALIZE) { 3712 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); 3713 error = copyin(nidp->nid_name, cp, nidp->nid_namelen); 3714 if (error != 0) { 3715 free(cp, M_NFSSTRING); 3716 goto out; 3717 } 3718 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) { 3719 /* 3720 * Free up all the old stuff and reinitialize hash 3721 * lists. All mutexes for both lists must be locked, 3722 * with the user/group name ones before the uid/gid 3723 * ones, to avoid a LOR. 3724 */ 3725 for (i = 0; i < nfsrv_lughashsize; i++) 3726 mtx_lock(&nfsusernamehash[i].mtx); 3727 for (i = 0; i < nfsrv_lughashsize; i++) 3728 mtx_lock(&nfsuserhash[i].mtx); 3729 for (i = 0; i < nfsrv_lughashsize; i++) 3730 TAILQ_FOREACH_SAFE(usrp, 3731 &nfsuserhash[i].lughead, lug_numhash, nusrp) 3732 nfsrv_removeuser(usrp, 1); 3733 for (i = 0; i < nfsrv_lughashsize; i++) 3734 mtx_unlock(&nfsuserhash[i].mtx); 3735 for (i = 0; i < nfsrv_lughashsize; i++) 3736 mtx_unlock(&nfsusernamehash[i].mtx); 3737 for (i = 0; i < nfsrv_lughashsize; i++) 3738 mtx_lock(&nfsgroupnamehash[i].mtx); 3739 for (i = 0; i < nfsrv_lughashsize; i++) 3740 mtx_lock(&nfsgrouphash[i].mtx); 3741 for (i = 0; i < nfsrv_lughashsize; i++) 3742 TAILQ_FOREACH_SAFE(usrp, 3743 &nfsgrouphash[i].lughead, lug_numhash, 3744 nusrp) 3745 nfsrv_removeuser(usrp, 0); 3746 for (i = 0; i < nfsrv_lughashsize; i++) 3747 mtx_unlock(&nfsgrouphash[i].mtx); 3748 for (i = 0; i < nfsrv_lughashsize; i++) 3749 mtx_unlock(&nfsgroupnamehash[i].mtx); 3750 free(nfsrv_dnsname, M_NFSSTRING); 3751 nfsrv_dnsname = NULL; 3752 } 3753 if (nfsuserhash == NULL) { 3754 /* Allocate the hash tables. */ 3755 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) * 3756 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3757 M_ZERO); 3758 for (i = 0; i < nfsrv_lughashsize; i++) 3759 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash", 3760 NULL, MTX_DEF | MTX_DUPOK); 3761 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) * 3762 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3763 M_ZERO); 3764 for (i = 0; i < nfsrv_lughashsize; i++) 3765 mtx_init(&nfsusernamehash[i].mtx, 3766 "nfsusrhash", NULL, MTX_DEF | 3767 MTX_DUPOK); 3768 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) * 3769 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3770 M_ZERO); 3771 for (i = 0; i < nfsrv_lughashsize; i++) 3772 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash", 3773 NULL, MTX_DEF | MTX_DUPOK); 3774 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) * 3775 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3776 M_ZERO); 3777 for (i = 0; i < nfsrv_lughashsize; i++) 3778 mtx_init(&nfsgroupnamehash[i].mtx, 3779 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK); 3780 } 3781 /* (Re)initialize the list heads. */ 3782 for (i = 0; i < nfsrv_lughashsize; i++) 3783 TAILQ_INIT(&nfsuserhash[i].lughead); 3784 for (i = 0; i < nfsrv_lughashsize; i++) 3785 TAILQ_INIT(&nfsusernamehash[i].lughead); 3786 for (i = 0; i < nfsrv_lughashsize; i++) 3787 TAILQ_INIT(&nfsgrouphash[i].lughead); 3788 for (i = 0; i < nfsrv_lughashsize; i++) 3789 TAILQ_INIT(&nfsgroupnamehash[i].lughead); 3790 3791 /* 3792 * Put name in "DNS" string. 3793 */ 3794 nfsrv_dnsname = cp; 3795 nfsrv_defaultuid = nidp->nid_uid; 3796 nfsrv_defaultgid = nidp->nid_gid; 3797 nfsrv_usercnt = 0; 3798 nfsrv_usermax = nidp->nid_usermax; 3799 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen); 3800 goto out; 3801 } 3802 3803 /* 3804 * malloc the new one now, so any potential sleep occurs before 3805 * manipulation of the lists. 3806 */ 3807 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, 3808 M_NFSUSERGROUP, M_WAITOK | M_ZERO); 3809 error = copyin(nidp->nid_name, newusrp->lug_name, 3810 nidp->nid_namelen); 3811 if (error == 0 && nidp->nid_ngroup > 0 && 3812 (nidp->nid_flag & NFSID_ADDUID) != 0) { 3813 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP, 3814 M_WAITOK); 3815 error = copyin(nidp->nid_grps, grps, 3816 sizeof(gid_t) * nidp->nid_ngroup); 3817 if (error == 0) { 3818 /* 3819 * Create a credential just like svc_getcred(), 3820 * but using the group list provided. 3821 */ 3822 cr = crget(); 3823 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; 3824 crsetgroups(cr, nidp->nid_ngroup, grps); 3825 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; 3826 cr->cr_prison = &prison0; 3827 prison_hold(cr->cr_prison); 3828 #ifdef MAC 3829 mac_cred_associate_nfsd(cr); 3830 #endif 3831 newusrp->lug_cred = cr; 3832 } 3833 free(grps, M_TEMP); 3834 } 3835 if (error) { 3836 free(newusrp, M_NFSUSERGROUP); 3837 goto out; 3838 } 3839 newusrp->lug_namelen = nidp->nid_namelen; 3840 3841 /* 3842 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed 3843 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group. 3844 * The flags user_locked, username_locked, group_locked and 3845 * groupname_locked are set to indicate all of those hash lists are 3846 * locked. hp_name != NULL and hp_idnum != NULL indicates that 3847 * the respective one mutex is locked. 3848 */ 3849 user_locked = username_locked = group_locked = groupname_locked = 0; 3850 hp_name = hp_idnum = NULL; 3851 3852 /* 3853 * Delete old entries, as required. 3854 */ 3855 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3856 /* Must lock all username hash lists first, to avoid a LOR. */ 3857 for (i = 0; i < nfsrv_lughashsize; i++) 3858 mtx_lock(&nfsusernamehash[i].mtx); 3859 username_locked = 1; 3860 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3861 mtx_lock(&hp_idnum->mtx); 3862 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3863 nusrp) { 3864 if (usrp->lug_uid == nidp->nid_uid) 3865 nfsrv_removeuser(usrp, 1); 3866 } 3867 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3868 hp_name = NFSUSERNAMEHASH(newusrp->lug_name, 3869 newusrp->lug_namelen); 3870 mtx_lock(&hp_name->mtx); 3871 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3872 nusrp) { 3873 if (usrp->lug_namelen == newusrp->lug_namelen && 3874 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3875 usrp->lug_namelen)) { 3876 thp = NFSUSERHASH(usrp->lug_uid); 3877 mtx_lock(&thp->mtx); 3878 nfsrv_removeuser(usrp, 1); 3879 mtx_unlock(&thp->mtx); 3880 } 3881 } 3882 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3883 mtx_lock(&hp_idnum->mtx); 3884 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3885 /* Must lock all groupname hash lists first, to avoid a LOR. */ 3886 for (i = 0; i < nfsrv_lughashsize; i++) 3887 mtx_lock(&nfsgroupnamehash[i].mtx); 3888 groupname_locked = 1; 3889 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3890 mtx_lock(&hp_idnum->mtx); 3891 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3892 nusrp) { 3893 if (usrp->lug_gid == nidp->nid_gid) 3894 nfsrv_removeuser(usrp, 0); 3895 } 3896 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3897 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name, 3898 newusrp->lug_namelen); 3899 mtx_lock(&hp_name->mtx); 3900 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3901 nusrp) { 3902 if (usrp->lug_namelen == newusrp->lug_namelen && 3903 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3904 usrp->lug_namelen)) { 3905 thp = NFSGROUPHASH(usrp->lug_gid); 3906 mtx_lock(&thp->mtx); 3907 nfsrv_removeuser(usrp, 0); 3908 mtx_unlock(&thp->mtx); 3909 } 3910 } 3911 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3912 mtx_lock(&hp_idnum->mtx); 3913 } 3914 3915 /* 3916 * Now, we can add the new one. 3917 */ 3918 if (nidp->nid_usertimeout) 3919 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3920 else 3921 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3922 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3923 newusrp->lug_uid = nidp->nid_uid; 3924 thp = NFSUSERHASH(newusrp->lug_uid); 3925 mtx_assert(&thp->mtx, MA_OWNED); 3926 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3927 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3928 mtx_assert(&thp->mtx, MA_OWNED); 3929 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3930 atomic_add_int(&nfsrv_usercnt, 1); 3931 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3932 newusrp->lug_gid = nidp->nid_gid; 3933 thp = NFSGROUPHASH(newusrp->lug_gid); 3934 mtx_assert(&thp->mtx, MA_OWNED); 3935 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3936 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3937 mtx_assert(&thp->mtx, MA_OWNED); 3938 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3939 atomic_add_int(&nfsrv_usercnt, 1); 3940 } else { 3941 if (newusrp->lug_cred != NULL) 3942 crfree(newusrp->lug_cred); 3943 free(newusrp, M_NFSUSERGROUP); 3944 } 3945 3946 /* 3947 * Once per second, allow one thread to trim the cache. 3948 */ 3949 if (lasttime < NFSD_MONOSEC && 3950 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) { 3951 /* 3952 * First, unlock the single mutexes, so that all entries 3953 * can be locked and any LOR is avoided. 3954 */ 3955 if (hp_name != NULL) { 3956 mtx_unlock(&hp_name->mtx); 3957 hp_name = NULL; 3958 } 3959 if (hp_idnum != NULL) { 3960 mtx_unlock(&hp_idnum->mtx); 3961 hp_idnum = NULL; 3962 } 3963 3964 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID | 3965 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) { 3966 if (username_locked == 0) { 3967 for (i = 0; i < nfsrv_lughashsize; i++) 3968 mtx_lock(&nfsusernamehash[i].mtx); 3969 username_locked = 1; 3970 } 3971 KASSERT(user_locked == 0, 3972 ("nfssvc_idname: user_locked")); 3973 for (i = 0; i < nfsrv_lughashsize; i++) 3974 mtx_lock(&nfsuserhash[i].mtx); 3975 user_locked = 1; 3976 for (i = 0; i < nfsrv_lughashsize; i++) { 3977 TAILQ_FOREACH_SAFE(usrp, 3978 &nfsuserhash[i].lughead, lug_numhash, 3979 nusrp) 3980 if (usrp->lug_expiry < NFSD_MONOSEC) 3981 nfsrv_removeuser(usrp, 1); 3982 } 3983 for (i = 0; i < nfsrv_lughashsize; i++) { 3984 /* 3985 * Trim the cache using an approximate LRU 3986 * algorithm. This code deletes the least 3987 * recently used entry on each hash list. 3988 */ 3989 if (nfsrv_usercnt <= nfsrv_usermax) 3990 break; 3991 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead); 3992 if (usrp != NULL) 3993 nfsrv_removeuser(usrp, 1); 3994 } 3995 } else { 3996 if (groupname_locked == 0) { 3997 for (i = 0; i < nfsrv_lughashsize; i++) 3998 mtx_lock(&nfsgroupnamehash[i].mtx); 3999 groupname_locked = 1; 4000 } 4001 KASSERT(group_locked == 0, 4002 ("nfssvc_idname: group_locked")); 4003 for (i = 0; i < nfsrv_lughashsize; i++) 4004 mtx_lock(&nfsgrouphash[i].mtx); 4005 group_locked = 1; 4006 for (i = 0; i < nfsrv_lughashsize; i++) { 4007 TAILQ_FOREACH_SAFE(usrp, 4008 &nfsgrouphash[i].lughead, lug_numhash, 4009 nusrp) 4010 if (usrp->lug_expiry < NFSD_MONOSEC) 4011 nfsrv_removeuser(usrp, 0); 4012 } 4013 for (i = 0; i < nfsrv_lughashsize; i++) { 4014 /* 4015 * Trim the cache using an approximate LRU 4016 * algorithm. This code deletes the least 4017 * recently user entry on each hash list. 4018 */ 4019 if (nfsrv_usercnt <= nfsrv_usermax) 4020 break; 4021 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead); 4022 if (usrp != NULL) 4023 nfsrv_removeuser(usrp, 0); 4024 } 4025 } 4026 lasttime = NFSD_MONOSEC; 4027 atomic_store_rel_int(&onethread, 0); 4028 } 4029 4030 /* Now, unlock all locked mutexes. */ 4031 if (hp_idnum != NULL) 4032 mtx_unlock(&hp_idnum->mtx); 4033 if (hp_name != NULL) 4034 mtx_unlock(&hp_name->mtx); 4035 if (user_locked != 0) 4036 for (i = 0; i < nfsrv_lughashsize; i++) 4037 mtx_unlock(&nfsuserhash[i].mtx); 4038 if (username_locked != 0) 4039 for (i = 0; i < nfsrv_lughashsize; i++) 4040 mtx_unlock(&nfsusernamehash[i].mtx); 4041 if (group_locked != 0) 4042 for (i = 0; i < nfsrv_lughashsize; i++) 4043 mtx_unlock(&nfsgrouphash[i].mtx); 4044 if (groupname_locked != 0) 4045 for (i = 0; i < nfsrv_lughashsize; i++) 4046 mtx_unlock(&nfsgroupnamehash[i].mtx); 4047 out: 4048 NFSEXITCODE(error); 4049 return (error); 4050 } 4051 4052 /* 4053 * Remove a user/group name element. 4054 */ 4055 static void 4056 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser) 4057 { 4058 struct nfsrv_lughash *hp; 4059 4060 if (isuser != 0) { 4061 hp = NFSUSERHASH(usrp->lug_uid); 4062 mtx_assert(&hp->mtx, MA_OWNED); 4063 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4064 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen); 4065 mtx_assert(&hp->mtx, MA_OWNED); 4066 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 4067 } else { 4068 hp = NFSGROUPHASH(usrp->lug_gid); 4069 mtx_assert(&hp->mtx, MA_OWNED); 4070 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4071 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen); 4072 mtx_assert(&hp->mtx, MA_OWNED); 4073 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 4074 } 4075 atomic_add_int(&nfsrv_usercnt, -1); 4076 if (usrp->lug_cred != NULL) 4077 crfree(usrp->lug_cred); 4078 free(usrp, M_NFSUSERGROUP); 4079 } 4080 4081 /* 4082 * Free up all the allocations related to the name<-->id cache. 4083 * This function should only be called when the nfsuserd daemon isn't 4084 * running, since it doesn't do any locking. 4085 * This function is meant to be used when the nfscommon module is unloaded. 4086 */ 4087 void 4088 nfsrv_cleanusergroup(void) 4089 { 4090 struct nfsrv_lughash *hp, *hp2; 4091 struct nfsusrgrp *nusrp, *usrp; 4092 int i; 4093 4094 if (nfsuserhash == NULL) 4095 return; 4096 4097 for (i = 0; i < nfsrv_lughashsize; i++) { 4098 hp = &nfsuserhash[i]; 4099 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 4100 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4101 hp2 = NFSUSERNAMEHASH(usrp->lug_name, 4102 usrp->lug_namelen); 4103 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 4104 if (usrp->lug_cred != NULL) 4105 crfree(usrp->lug_cred); 4106 free(usrp, M_NFSUSERGROUP); 4107 } 4108 hp = &nfsgrouphash[i]; 4109 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 4110 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 4111 hp2 = NFSGROUPNAMEHASH(usrp->lug_name, 4112 usrp->lug_namelen); 4113 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 4114 if (usrp->lug_cred != NULL) 4115 crfree(usrp->lug_cred); 4116 free(usrp, M_NFSUSERGROUP); 4117 } 4118 mtx_destroy(&nfsuserhash[i].mtx); 4119 mtx_destroy(&nfsusernamehash[i].mtx); 4120 mtx_destroy(&nfsgroupnamehash[i].mtx); 4121 mtx_destroy(&nfsgrouphash[i].mtx); 4122 } 4123 free(nfsuserhash, M_NFSUSERGROUP); 4124 free(nfsusernamehash, M_NFSUSERGROUP); 4125 free(nfsgrouphash, M_NFSUSERGROUP); 4126 free(nfsgroupnamehash, M_NFSUSERGROUP); 4127 free(nfsrv_dnsname, M_NFSSTRING); 4128 } 4129 4130 /* 4131 * This function scans a byte string and checks for UTF-8 compliance. 4132 * It returns 0 if it conforms and NFSERR_INVAL if not. 4133 */ 4134 int 4135 nfsrv_checkutf8(u_int8_t *cp, int len) 4136 { 4137 u_int32_t val = 0x0; 4138 int cnt = 0, gotd = 0, shift = 0; 4139 u_int8_t byte; 4140 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 4141 int error = 0; 4142 4143 /* 4144 * Here are what the variables are used for: 4145 * val - the calculated value of a multibyte char, used to check 4146 * that it was coded with the correct range 4147 * cnt - the number of 10xxxxxx bytes to follow 4148 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 4149 * shift - lower order bits of range (ie. "val >> shift" should 4150 * not be 0, in other words, dividing by the lower bound 4151 * of the range should get a non-zero value) 4152 * byte - used to calculate cnt 4153 */ 4154 while (len > 0) { 4155 if (cnt > 0) { 4156 /* This handles the 10xxxxxx bytes */ 4157 if ((*cp & 0xc0) != 0x80 || 4158 (gotd && (*cp & 0x20))) { 4159 error = NFSERR_INVAL; 4160 goto out; 4161 } 4162 gotd = 0; 4163 val <<= 6; 4164 val |= (*cp & 0x3f); 4165 cnt--; 4166 if (cnt == 0 && (val >> shift) == 0x0) { 4167 error = NFSERR_INVAL; 4168 goto out; 4169 } 4170 } else if (*cp & 0x80) { 4171 /* first byte of multi byte char */ 4172 byte = *cp; 4173 while ((byte & 0x40) && cnt < 6) { 4174 cnt++; 4175 byte <<= 1; 4176 } 4177 if (cnt == 0 || cnt == 6) { 4178 error = NFSERR_INVAL; 4179 goto out; 4180 } 4181 val = (*cp & (0x3f >> cnt)); 4182 shift = utf8_shift[cnt - 1]; 4183 if (cnt == 2 && val == 0xd) 4184 /* Check for the 0xd800-0xdfff case */ 4185 gotd = 1; 4186 } 4187 cp++; 4188 len--; 4189 } 4190 if (cnt > 0) 4191 error = NFSERR_INVAL; 4192 4193 out: 4194 NFSEXITCODE(error); 4195 return (error); 4196 } 4197 4198 /* 4199 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 4200 * strings, one with the root path in it and the other with the list of 4201 * locations. The list is in the same format as is found in nfr_refs. 4202 * It is a "," separated list of entries, where each of them is of the 4203 * form <server>:<rootpath>. For example 4204 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 4205 * The nilp argument is set to 1 for the special case of a null fs_root 4206 * and an empty server list. 4207 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 4208 * number of xdr bytes parsed in sump. 4209 */ 4210 static int 4211 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 4212 int *sump, int *nilp) 4213 { 4214 u_int32_t *tl; 4215 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 4216 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 4217 struct list { 4218 SLIST_ENTRY(list) next; 4219 int len; 4220 u_char host[1]; 4221 } *lsp, *nlsp; 4222 SLIST_HEAD(, list) head; 4223 4224 *fsrootp = NULL; 4225 *srvp = NULL; 4226 *nilp = 0; 4227 4228 /* 4229 * Get the fs_root path and check for the special case of null path 4230 * and 0 length server list. 4231 */ 4232 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4233 len = fxdr_unsigned(int, *tl); 4234 if (len < 0 || len > 10240) { 4235 error = NFSERR_BADXDR; 4236 goto nfsmout; 4237 } 4238 if (len == 0) { 4239 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4240 if (*tl != 0) { 4241 error = NFSERR_BADXDR; 4242 goto nfsmout; 4243 } 4244 *nilp = 1; 4245 *sump = 2 * NFSX_UNSIGNED; 4246 error = 0; 4247 goto nfsmout; 4248 } 4249 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 4250 error = nfsrv_mtostr(nd, cp, len); 4251 if (!error) { 4252 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4253 cnt = fxdr_unsigned(int, *tl); 4254 if (cnt <= 0) 4255 error = NFSERR_BADXDR; 4256 } 4257 if (error) 4258 goto nfsmout; 4259 4260 /* 4261 * Now, loop through the location list and make up the srvlist. 4262 */ 4263 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 4264 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 4265 slen = 1024; 4266 siz = 0; 4267 for (i = 0; i < cnt; i++) { 4268 SLIST_INIT(&head); 4269 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4270 nsrv = fxdr_unsigned(int, *tl); 4271 if (nsrv <= 0) { 4272 error = NFSERR_BADXDR; 4273 goto nfsmout; 4274 } 4275 4276 /* 4277 * Handle the first server by putting it in the srvstr. 4278 */ 4279 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4280 len = fxdr_unsigned(int, *tl); 4281 if (len <= 0 || len > 1024) { 4282 error = NFSERR_BADXDR; 4283 goto nfsmout; 4284 } 4285 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 4286 if (cp3 != cp2) { 4287 *cp3++ = ','; 4288 siz++; 4289 } 4290 error = nfsrv_mtostr(nd, cp3, len); 4291 if (error) 4292 goto nfsmout; 4293 cp3 += len; 4294 *cp3++ = ':'; 4295 siz += (len + 1); 4296 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 4297 for (j = 1; j < nsrv; j++) { 4298 /* 4299 * Yuck, put them in an slist and process them later. 4300 */ 4301 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4302 len = fxdr_unsigned(int, *tl); 4303 if (len <= 0 || len > 1024) { 4304 error = NFSERR_BADXDR; 4305 goto nfsmout; 4306 } 4307 lsp = (struct list *)malloc(sizeof (struct list) 4308 + len, M_TEMP, M_WAITOK); 4309 error = nfsrv_mtostr(nd, lsp->host, len); 4310 if (error) 4311 goto nfsmout; 4312 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 4313 lsp->len = len; 4314 SLIST_INSERT_HEAD(&head, lsp, next); 4315 } 4316 4317 /* 4318 * Finally, we can get the path. 4319 */ 4320 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4321 len = fxdr_unsigned(int, *tl); 4322 if (len <= 0 || len > 1024) { 4323 error = NFSERR_BADXDR; 4324 goto nfsmout; 4325 } 4326 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 4327 error = nfsrv_mtostr(nd, cp3, len); 4328 if (error) 4329 goto nfsmout; 4330 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 4331 str = cp3; 4332 stringlen = len; 4333 cp3 += len; 4334 siz += len; 4335 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 4336 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 4337 &cp2, &cp3, &slen); 4338 *cp3++ = ','; 4339 NFSBCOPY(lsp->host, cp3, lsp->len); 4340 cp3 += lsp->len; 4341 *cp3++ = ':'; 4342 NFSBCOPY(str, cp3, stringlen); 4343 cp3 += stringlen; 4344 *cp3 = '\0'; 4345 siz += (lsp->len + stringlen + 2); 4346 free(lsp, M_TEMP); 4347 } 4348 } 4349 *fsrootp = cp; 4350 *srvp = cp2; 4351 *sump = xdrsum; 4352 NFSEXITCODE2(0, nd); 4353 return (0); 4354 nfsmout: 4355 if (cp != NULL) 4356 free(cp, M_NFSSTRING); 4357 if (cp2 != NULL) 4358 free(cp2, M_NFSSTRING); 4359 NFSEXITCODE2(error, nd); 4360 return (error); 4361 } 4362 4363 /* 4364 * Make the malloc'd space large enough. This is a pain, but the xdr 4365 * doesn't set an upper bound on the side, so... 4366 */ 4367 static void 4368 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 4369 { 4370 u_char *cp; 4371 int i; 4372 4373 if (siz <= *slenp) 4374 return; 4375 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 4376 NFSBCOPY(*cpp, cp, *slenp); 4377 free(*cpp, M_NFSSTRING); 4378 i = *cpp2 - *cpp; 4379 *cpp = cp; 4380 *cpp2 = cp + i; 4381 *slenp = siz + 1024; 4382 } 4383 4384 /* 4385 * Initialize the reply header data structures. 4386 */ 4387 void 4388 nfsrvd_rephead(struct nfsrv_descript *nd) 4389 { 4390 struct mbuf *mreq; 4391 4392 /* 4393 * If this is a big reply, use a cluster. 4394 */ 4395 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 4396 nfs_bigreply[nd->nd_procnum]) { 4397 NFSMCLGET(mreq, M_WAITOK); 4398 nd->nd_mreq = mreq; 4399 nd->nd_mb = mreq; 4400 } else { 4401 NFSMGET(mreq); 4402 nd->nd_mreq = mreq; 4403 nd->nd_mb = mreq; 4404 } 4405 nd->nd_bpos = mtod(mreq, caddr_t); 4406 mreq->m_len = 0; 4407 4408 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 4409 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 4410 } 4411 4412 /* 4413 * Lock a socket against others. 4414 * Currently used to serialize connect/disconnect attempts. 4415 */ 4416 int 4417 newnfs_sndlock(int *flagp) 4418 { 4419 struct timespec ts; 4420 4421 NFSLOCKSOCK(); 4422 while (*flagp & NFSR_SNDLOCK) { 4423 *flagp |= NFSR_WANTSND; 4424 ts.tv_sec = 0; 4425 ts.tv_nsec = 0; 4426 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 4427 PZERO - 1, "nfsndlck", &ts); 4428 } 4429 *flagp |= NFSR_SNDLOCK; 4430 NFSUNLOCKSOCK(); 4431 return (0); 4432 } 4433 4434 /* 4435 * Unlock the stream socket for others. 4436 */ 4437 void 4438 newnfs_sndunlock(int *flagp) 4439 { 4440 4441 NFSLOCKSOCK(); 4442 if ((*flagp & NFSR_SNDLOCK) == 0) 4443 panic("nfs sndunlock"); 4444 *flagp &= ~NFSR_SNDLOCK; 4445 if (*flagp & NFSR_WANTSND) { 4446 *flagp &= ~NFSR_WANTSND; 4447 wakeup((caddr_t)flagp); 4448 } 4449 NFSUNLOCKSOCK(); 4450 } 4451 4452 int 4453 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin, 4454 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp) 4455 { 4456 struct in_addr saddr; 4457 uint32_t portnum, *tl; 4458 int i, j, k; 4459 sa_family_t af = AF_UNSPEC; 4460 char addr[64], protocol[5], *cp; 4461 int cantparse = 0, error = 0; 4462 uint16_t portv; 4463 4464 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4465 i = fxdr_unsigned(int, *tl); 4466 if (i >= 3 && i <= 4) { 4467 error = nfsrv_mtostr(nd, protocol, i); 4468 if (error) 4469 goto nfsmout; 4470 if (strcmp(protocol, "tcp") == 0) { 4471 af = AF_INET; 4472 *isudp = 0; 4473 } else if (strcmp(protocol, "udp") == 0) { 4474 af = AF_INET; 4475 *isudp = 1; 4476 } else if (strcmp(protocol, "tcp6") == 0) { 4477 af = AF_INET6; 4478 *isudp = 0; 4479 } else if (strcmp(protocol, "udp6") == 0) { 4480 af = AF_INET6; 4481 *isudp = 1; 4482 } else 4483 cantparse = 1; 4484 } else { 4485 cantparse = 1; 4486 if (i > 0) { 4487 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4488 if (error) 4489 goto nfsmout; 4490 } 4491 } 4492 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4493 i = fxdr_unsigned(int, *tl); 4494 if (i < 0) { 4495 error = NFSERR_BADXDR; 4496 goto nfsmout; 4497 } else if (cantparse == 0 && i >= 11 && i < 64) { 4498 /* 4499 * The shortest address is 11chars and the longest is < 64. 4500 */ 4501 error = nfsrv_mtostr(nd, addr, i); 4502 if (error) 4503 goto nfsmout; 4504 4505 /* Find the port# at the end and extract that. */ 4506 i = strlen(addr); 4507 k = 0; 4508 cp = &addr[i - 1]; 4509 /* Count back two '.'s from end to get port# field. */ 4510 for (j = 0; j < i; j++) { 4511 if (*cp == '.') { 4512 k++; 4513 if (k == 2) 4514 break; 4515 } 4516 cp--; 4517 } 4518 if (k == 2) { 4519 /* 4520 * The NFSv4 port# is appended as .N.N, where N is 4521 * a decimal # in the range 0-255, just like an inet4 4522 * address. Cheat and use inet_aton(), which will 4523 * return a Class A address and then shift the high 4524 * order 8bits over to convert it to the port#. 4525 */ 4526 *cp++ = '\0'; 4527 if (inet_aton(cp, &saddr) == 1) { 4528 portnum = ntohl(saddr.s_addr); 4529 portv = (uint16_t)((portnum >> 16) | 4530 (portnum & 0xff)); 4531 } else 4532 cantparse = 1; 4533 } else 4534 cantparse = 1; 4535 if (cantparse == 0) { 4536 if (af == AF_INET) { 4537 if (inet_pton(af, addr, &sin->sin_addr) == 1) { 4538 sin->sin_len = sizeof(*sin); 4539 sin->sin_family = AF_INET; 4540 sin->sin_port = htons(portv); 4541 *saf = af; 4542 return (0); 4543 } 4544 } else { 4545 if (inet_pton(af, addr, &sin6->sin6_addr) 4546 == 1) { 4547 sin6->sin6_len = sizeof(*sin6); 4548 sin6->sin6_family = AF_INET6; 4549 sin6->sin6_port = htons(portv); 4550 *saf = af; 4551 return (0); 4552 } 4553 } 4554 } 4555 } else { 4556 if (i > 0) { 4557 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4558 if (error) 4559 goto nfsmout; 4560 } 4561 } 4562 error = EPERM; 4563 nfsmout: 4564 return (error); 4565 } 4566 4567 /* 4568 * Handle an NFSv4.1 Sequence request for the session. 4569 * If reply != NULL, use it to return the cached reply, as required. 4570 * The client gets a cached reply via this call for callbacks, however the 4571 * server gets a cached reply via the nfsv4_seqsess_cachereply() call. 4572 */ 4573 int 4574 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 4575 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 4576 { 4577 int error; 4578 4579 error = 0; 4580 if (reply != NULL) 4581 *reply = NULL; 4582 if (slotid > maxslot) 4583 return (NFSERR_BADSLOT); 4584 if (seqid == slots[slotid].nfssl_seq) { 4585 /* A retry. */ 4586 if (slots[slotid].nfssl_inprog != 0) 4587 error = NFSERR_DELAY; 4588 else if (slots[slotid].nfssl_reply != NULL) { 4589 if (reply != NULL) { 4590 *reply = slots[slotid].nfssl_reply; 4591 slots[slotid].nfssl_reply = NULL; 4592 } 4593 slots[slotid].nfssl_inprog = 1; 4594 error = NFSERR_REPLYFROMCACHE; 4595 } else 4596 /* No reply cached, so just do it. */ 4597 slots[slotid].nfssl_inprog = 1; 4598 } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 4599 if (slots[slotid].nfssl_reply != NULL) 4600 m_freem(slots[slotid].nfssl_reply); 4601 slots[slotid].nfssl_reply = NULL; 4602 slots[slotid].nfssl_inprog = 1; 4603 slots[slotid].nfssl_seq++; 4604 } else 4605 error = NFSERR_SEQMISORDERED; 4606 return (error); 4607 } 4608 4609 /* 4610 * Cache this reply for the slot. 4611 * Use the "rep" argument to return the cached reply if repstat is set to 4612 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value. 4613 */ 4614 void 4615 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat, 4616 struct mbuf **rep) 4617 { 4618 4619 if (repstat == NFSERR_REPLYFROMCACHE) { 4620 *rep = slots[slotid].nfssl_reply; 4621 slots[slotid].nfssl_reply = NULL; 4622 } else { 4623 if (slots[slotid].nfssl_reply != NULL) 4624 m_freem(slots[slotid].nfssl_reply); 4625 slots[slotid].nfssl_reply = *rep; 4626 } 4627 slots[slotid].nfssl_inprog = 0; 4628 } 4629 4630 /* 4631 * Generate the xdr for an NFSv4.1 Sequence Operation. 4632 */ 4633 void 4634 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, 4635 struct nfsclsession *sep, int dont_replycache) 4636 { 4637 uint32_t *tl, slotseq = 0; 4638 int error, maxslot, slotpos; 4639 uint8_t sessionid[NFSX_V4SESSIONID]; 4640 4641 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq, 4642 sessionid); 4643 nd->nd_maxreq = sep->nfsess_maxreq; 4644 nd->nd_maxresp = sep->nfsess_maxresp; 4645 4646 /* Build the Sequence arguments. */ 4647 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 4648 nd->nd_sequence = tl; 4649 bcopy(sessionid, tl, NFSX_V4SESSIONID); 4650 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4651 nd->nd_slotseq = tl; 4652 if (error == 0) { 4653 nd->nd_flag |= ND_HASSLOTID; 4654 nd->nd_slotid = slotpos; 4655 *tl++ = txdr_unsigned(slotseq); 4656 *tl++ = txdr_unsigned(slotpos); 4657 *tl++ = txdr_unsigned(maxslot); 4658 if (dont_replycache == 0) 4659 *tl = newnfs_true; 4660 else 4661 *tl = newnfs_false; 4662 } else { 4663 /* 4664 * There are two errors and the rest of the session can 4665 * just be zeros. 4666 * NFSERR_BADSESSION: This bad session should just generate 4667 * the same error again when the RPC is retried. 4668 * ESTALE: A forced dismount is in progress and will cause the 4669 * RPC to fail later. 4670 */ 4671 *tl++ = 0; 4672 *tl++ = 0; 4673 *tl++ = 0; 4674 *tl = 0; 4675 } 4676 nd->nd_flag |= ND_HASSEQUENCE; 4677 } 4678 4679 int 4680 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep, 4681 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid) 4682 { 4683 int i, maxslot, slotpos; 4684 uint64_t bitval; 4685 4686 /* Find an unused slot. */ 4687 slotpos = -1; 4688 maxslot = -1; 4689 mtx_lock(&sep->nfsess_mtx); 4690 do { 4691 if (nmp != NULL && sep->nfsess_defunct != 0) { 4692 /* Just return the bad session. */ 4693 bcopy(sep->nfsess_sessionid, sessionid, 4694 NFSX_V4SESSIONID); 4695 mtx_unlock(&sep->nfsess_mtx); 4696 return (NFSERR_BADSESSION); 4697 } 4698 bitval = 1; 4699 for (i = 0; i < sep->nfsess_foreslots; i++) { 4700 if ((bitval & sep->nfsess_slots) == 0) { 4701 slotpos = i; 4702 sep->nfsess_slots |= bitval; 4703 sep->nfsess_slotseq[i]++; 4704 *slotseqp = sep->nfsess_slotseq[i]; 4705 break; 4706 } 4707 bitval <<= 1; 4708 } 4709 if (slotpos == -1) { 4710 /* 4711 * If a forced dismount is in progress, just return. 4712 * This RPC attempt will fail when it calls 4713 * newnfs_request(). 4714 */ 4715 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) { 4716 mtx_unlock(&sep->nfsess_mtx); 4717 return (ESTALE); 4718 } 4719 /* Wake up once/sec, to check for a forced dismount. */ 4720 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 4721 PZERO, "nfsclseq", hz); 4722 } 4723 } while (slotpos == -1); 4724 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 4725 bitval = 1; 4726 for (i = 0; i < 64; i++) { 4727 if ((bitval & sep->nfsess_slots) != 0) 4728 maxslot = i; 4729 bitval <<= 1; 4730 } 4731 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 4732 mtx_unlock(&sep->nfsess_mtx); 4733 *slotposp = slotpos; 4734 *maxslotp = maxslot; 4735 return (0); 4736 } 4737 4738 /* 4739 * Free a session slot. 4740 */ 4741 void 4742 nfsv4_freeslot(struct nfsclsession *sep, int slot) 4743 { 4744 uint64_t bitval; 4745 4746 bitval = 1; 4747 if (slot > 0) 4748 bitval <<= slot; 4749 mtx_lock(&sep->nfsess_mtx); 4750 if ((bitval & sep->nfsess_slots) == 0) 4751 printf("freeing free slot!!\n"); 4752 sep->nfsess_slots &= ~bitval; 4753 wakeup(&sep->nfsess_slots); 4754 mtx_unlock(&sep->nfsess_mtx); 4755 } 4756 4757 /* 4758 * Search for a matching pnfsd DS, based on the nmp arg. 4759 * Return one if found, NULL otherwise. 4760 */ 4761 struct nfsdevice * 4762 nfsv4_findmirror(struct nfsmount *nmp) 4763 { 4764 struct nfsdevice *ds; 4765 4766 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED); 4767 /* 4768 * Search the DS server list for a match with nmp. 4769 */ 4770 if (nfsrv_devidcnt == 0) 4771 return (NULL); 4772 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) { 4773 if (ds->nfsdev_nmp == nmp) { 4774 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n"); 4775 break; 4776 } 4777 } 4778 return (ds); 4779 } 4780 4781 /* 4782 * Fill in the fields of "struct nfsrv_descript". 4783 */ 4784 void 4785 nfsm_set(struct nfsrv_descript *nd, u_int offs) 4786 { 4787 struct mbuf *m; 4788 4789 m = nd->nd_mb; 4790 nd->nd_bpos = mtod(m, char *) + offs; 4791 } 4792