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