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