1 1.63 hannken /* $NetBSD: nfs_export.c,v 1.63 2021/06/04 10:44:58 hannken Exp $ */ 2 1.1 jmmv 3 1.1 jmmv /*- 4 1.61 ad * Copyright (c) 1997, 1998, 2004, 2005, 2008, 2019 The NetBSD Foundation, Inc. 5 1.1 jmmv * All rights reserved. 6 1.1 jmmv * 7 1.1 jmmv * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jmmv * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 1.1 jmmv * NASA Ames Research Center. 10 1.1 jmmv * This code is derived from software contributed to The NetBSD Foundation 11 1.1 jmmv * by Charles M. Hannum. 12 1.1 jmmv * This code is derived from software contributed to The NetBSD Foundation 13 1.1 jmmv * by Julio M. Merino Vidal. 14 1.1 jmmv * 15 1.1 jmmv * Redistribution and use in source and binary forms, with or without 16 1.1 jmmv * modification, are permitted provided that the following conditions 17 1.1 jmmv * are met: 18 1.1 jmmv * 1. Redistributions of source code must retain the above copyright 19 1.1 jmmv * notice, this list of conditions and the following disclaimer. 20 1.1 jmmv * 2. Redistributions in binary form must reproduce the above copyright 21 1.1 jmmv * notice, this list of conditions and the following disclaimer in the 22 1.1 jmmv * documentation and/or other materials provided with the distribution. 23 1.1 jmmv * 24 1.1 jmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 25 1.1 jmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 1.1 jmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 1.1 jmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 28 1.1 jmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 1.1 jmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 1.1 jmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 1.1 jmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 1.1 jmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 1.1 jmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 1.1 jmmv * POSSIBILITY OF SUCH DAMAGE. 35 1.1 jmmv */ 36 1.1 jmmv 37 1.1 jmmv /* 38 1.1 jmmv * Copyright (c) 1989, 1993 39 1.1 jmmv * The Regents of the University of California. All rights reserved. 40 1.1 jmmv * (c) UNIX System Laboratories, Inc. 41 1.1 jmmv * All or some portions of this file are derived from material licensed 42 1.1 jmmv * to the University of California by American Telephone and Telegraph 43 1.1 jmmv * Co. or Unix System Laboratories, Inc. and are reproduced herein with 44 1.1 jmmv * the permission of UNIX System Laboratories, Inc. 45 1.1 jmmv * 46 1.1 jmmv * Redistribution and use in source and binary forms, with or without 47 1.1 jmmv * modification, are permitted provided that the following conditions 48 1.1 jmmv * are met: 49 1.1 jmmv * 1. Redistributions of source code must retain the above copyright 50 1.1 jmmv * notice, this list of conditions and the following disclaimer. 51 1.1 jmmv * 2. Redistributions in binary form must reproduce the above copyright 52 1.1 jmmv * notice, this list of conditions and the following disclaimer in the 53 1.1 jmmv * documentation and/or other materials provided with the distribution. 54 1.1 jmmv * 3. Neither the name of the University nor the names of its contributors 55 1.1 jmmv * may be used to endorse or promote products derived from this software 56 1.1 jmmv * without specific prior written permission. 57 1.1 jmmv * 58 1.1 jmmv * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 1.1 jmmv * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 1.1 jmmv * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 1.1 jmmv * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 1.1 jmmv * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 1.1 jmmv * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 1.1 jmmv * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 1.1 jmmv * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 1.1 jmmv * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 1.1 jmmv * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 1.1 jmmv * SUCH DAMAGE. 69 1.1 jmmv * 70 1.1 jmmv * @(#)vfs_subr.c 8.13 (Berkeley) 4/18/94 71 1.1 jmmv */ 72 1.1 jmmv 73 1.1 jmmv /* 74 1.1 jmmv * VFS exports list management. 75 1.46 ad * 76 1.46 ad * Lock order: vfs_busy -> mnt_updating -> netexport_lock. 77 1.1 jmmv */ 78 1.1 jmmv 79 1.1 jmmv #include <sys/cdefs.h> 80 1.63 hannken __KERNEL_RCSID(0, "$NetBSD: nfs_export.c,v 1.63 2021/06/04 10:44:58 hannken Exp $"); 81 1.1 jmmv 82 1.1 jmmv #include <sys/param.h> 83 1.1 jmmv #include <sys/systm.h> 84 1.45 ad #include <sys/kernel.h> 85 1.1 jmmv #include <sys/queue.h> 86 1.1 jmmv #include <sys/proc.h> 87 1.1 jmmv #include <sys/mount.h> 88 1.1 jmmv #include <sys/vnode.h> 89 1.1 jmmv #include <sys/namei.h> 90 1.1 jmmv #include <sys/errno.h> 91 1.1 jmmv #include <sys/malloc.h> 92 1.1 jmmv #include <sys/domain.h> 93 1.1 jmmv #include <sys/mbuf.h> 94 1.1 jmmv #include <sys/dirent.h> 95 1.1 jmmv #include <sys/socket.h> /* XXX for AF_MAX */ 96 1.11 elad #include <sys/kauth.h> 97 1.1 jmmv 98 1.1 jmmv #include <net/radix.h> 99 1.1 jmmv 100 1.1 jmmv #include <netinet/in.h> 101 1.1 jmmv 102 1.1 jmmv #include <nfs/rpcv2.h> 103 1.1 jmmv #include <nfs/nfsproto.h> 104 1.1 jmmv #include <nfs/nfs.h> 105 1.1 jmmv #include <nfs/nfs_var.h> 106 1.1 jmmv 107 1.1 jmmv /* 108 1.1 jmmv * Network address lookup element. 109 1.1 jmmv */ 110 1.1 jmmv struct netcred { 111 1.1 jmmv struct radix_node netc_rnodes[2]; 112 1.1 jmmv int netc_refcnt; 113 1.1 jmmv int netc_exflags; 114 1.11 elad kauth_cred_t netc_anon; 115 1.1 jmmv }; 116 1.1 jmmv 117 1.1 jmmv /* 118 1.1 jmmv * Network export information. 119 1.1 jmmv */ 120 1.1 jmmv struct netexport { 121 1.57 christos TAILQ_ENTRY(netexport) ne_list; 122 1.5 yamt struct mount *ne_mount; 123 1.5 yamt struct netcred ne_defexported; /* Default export */ 124 1.5 yamt struct radix_node_head *ne_rtable[AF_MAX+1]; /* Individual exports */ 125 1.1 jmmv }; 126 1.57 christos TAILQ_HEAD(, netexport) netexport_list = 127 1.57 christos TAILQ_HEAD_INITIALIZER(netexport_list); 128 1.1 jmmv 129 1.1 jmmv /* Publicly exported file system. */ 130 1.1 jmmv struct nfs_public nfs_pub; 131 1.1 jmmv 132 1.1 jmmv /* 133 1.1 jmmv * Local prototypes. 134 1.1 jmmv */ 135 1.5 yamt static int init_exports(struct mount *, struct netexport **); 136 1.1 jmmv static int hang_addrlist(struct mount *, struct netexport *, 137 1.1 jmmv const struct export_args *); 138 1.1 jmmv static int sacheck(struct sockaddr *); 139 1.1 jmmv static int free_netcred(struct radix_node *, void *); 140 1.5 yamt static int export(struct netexport *, const struct export_args *); 141 1.1 jmmv static int setpublicfs(struct mount *, struct netexport *, 142 1.1 jmmv const struct export_args *); 143 1.5 yamt static struct netcred *netcred_lookup(struct netexport *, struct mbuf *); 144 1.5 yamt static struct netexport *netexport_lookup(const struct mount *); 145 1.5 yamt static struct netexport *netexport_lookup_byfsid(const fsid_t *); 146 1.12 yamt static void netexport_clear(struct netexport *); 147 1.5 yamt static void netexport_insert(struct netexport *); 148 1.5 yamt static void netexport_remove(struct netexport *); 149 1.8 yamt static void netexport_wrlock(void); 150 1.8 yamt static void netexport_wrunlock(void); 151 1.40 ad static int nfs_export_update_30(struct mount *mp, const char *path, void *); 152 1.40 ad 153 1.45 ad static krwlock_t netexport_lock; 154 1.1 jmmv 155 1.1 jmmv /* 156 1.1 jmmv * PUBLIC INTERFACE 157 1.1 jmmv */ 158 1.1 jmmv 159 1.1 jmmv /* 160 1.1 jmmv * Declare and initialize the file system export hooks. 161 1.1 jmmv */ 162 1.45 ad static void netexport_unmount(struct mount *); 163 1.1 jmmv 164 1.1 jmmv struct vfs_hooks nfs_export_hooks = { 165 1.40 ad { NULL, NULL }, 166 1.45 ad .vh_unmount = netexport_unmount, 167 1.40 ad .vh_reexport = nfs_export_update_30, 168 1.1 jmmv }; 169 1.1 jmmv 170 1.1 jmmv /* 171 1.1 jmmv * VFS unmount hook for NFS exports. 172 1.1 jmmv * 173 1.1 jmmv * Releases NFS exports list resources if the given mount point has some. 174 1.53 dholland * As allocation happens lazily, it may be that it doesn't have this 175 1.52 dholland * information, although it theoretically should. 176 1.1 jmmv */ 177 1.1 jmmv static void 178 1.45 ad netexport_unmount(struct mount *mp) 179 1.1 jmmv { 180 1.5 yamt struct netexport *ne; 181 1.1 jmmv 182 1.1 jmmv KASSERT(mp != NULL); 183 1.1 jmmv 184 1.8 yamt netexport_wrlock(); 185 1.5 yamt ne = netexport_lookup(mp); 186 1.5 yamt if (ne == NULL) { 187 1.8 yamt netexport_wrunlock(); 188 1.5 yamt return; 189 1.1 jmmv } 190 1.12 yamt netexport_clear(ne); 191 1.5 yamt netexport_remove(ne); 192 1.8 yamt netexport_wrunlock(); 193 1.43 pooka kmem_free(ne, sizeof(*ne)); 194 1.1 jmmv } 195 1.1 jmmv 196 1.45 ad void 197 1.45 ad netexport_init(void) 198 1.45 ad { 199 1.45 ad 200 1.45 ad rw_init(&netexport_lock); 201 1.45 ad } 202 1.45 ad 203 1.45 ad void 204 1.45 ad netexport_fini(void) 205 1.45 ad { 206 1.45 ad struct netexport *ne; 207 1.45 ad struct mount *mp; 208 1.45 ad int error; 209 1.45 ad 210 1.57 christos while (!TAILQ_EMPTY(&netexport_list)) { 211 1.45 ad netexport_wrlock(); 212 1.57 christos ne = TAILQ_FIRST(&netexport_list); 213 1.45 ad mp = ne->ne_mount; 214 1.60 hannken error = vfs_busy(mp); 215 1.45 ad netexport_wrunlock(); 216 1.45 ad if (error != 0) { 217 1.45 ad kpause("nfsfini", false, hz, NULL); 218 1.45 ad continue; 219 1.45 ad } 220 1.61 ad mutex_enter(mp->mnt_updating); /* mnt_flag */ 221 1.45 ad netexport_unmount(mp); 222 1.61 ad mutex_exit(mp->mnt_updating); /* mnt_flag */ 223 1.60 hannken vfs_unbusy(mp); 224 1.45 ad } 225 1.45 ad rw_destroy(&netexport_lock); 226 1.45 ad } 227 1.45 ad 228 1.45 ad 229 1.1 jmmv /* 230 1.1 jmmv * Atomically set the NFS exports list of the given file system, replacing 231 1.1 jmmv * it with a new list of entries. 232 1.1 jmmv * 233 1.1 jmmv * Returns zero on success or an appropriate error code otherwise. 234 1.1 jmmv * 235 1.1 jmmv * Helper function for the nfssvc(2) system call (NFSSVC_SETEXPORTSLIST 236 1.63 hannken * and NFSSVC_REPLACEEXPORTSLIST command). 237 1.1 jmmv */ 238 1.1 jmmv int 239 1.48 christos mountd_set_exports_list(const struct mountd_exports_list *mel, struct lwp *l, 240 1.63 hannken struct mount *nmp, int cmd) 241 1.1 jmmv { 242 1.1 jmmv int error; 243 1.1 jmmv size_t i; 244 1.1 jmmv struct mount *mp; 245 1.5 yamt struct netexport *ne; 246 1.49 dholland struct pathbuf *pb; 247 1.1 jmmv struct nameidata nd; 248 1.1 jmmv struct vnode *vp; 249 1.15 martin size_t fid_size; 250 1.1 jmmv 251 1.33 elad if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_NFS, 252 1.33 elad KAUTH_REQ_NETWORK_NFS_EXPORT, NULL, NULL, NULL) != 0) 253 1.1 jmmv return EPERM; 254 1.1 jmmv 255 1.53 dholland /* Look up the file system path. */ 256 1.49 dholland error = pathbuf_copyin(mel->mel_path, &pb); 257 1.49 dholland if (error) { 258 1.49 dholland return error; 259 1.49 dholland } 260 1.49 dholland NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, pb); 261 1.1 jmmv error = namei(&nd); 262 1.49 dholland if (error != 0) { 263 1.49 dholland pathbuf_destroy(pb); 264 1.1 jmmv return error; 265 1.49 dholland } 266 1.5 yamt vp = nd.ni_vp; 267 1.5 yamt mp = vp->v_mount; 268 1.48 christos KASSERT(nmp == NULL || nmp == mp); 269 1.49 dholland pathbuf_destroy(pb); 270 1.1 jmmv 271 1.41 pooka /* 272 1.41 pooka * Make sure the file system can do vptofh. If the file system 273 1.41 pooka * knows the handle's size, just trust it's able to do the 274 1.41 pooka * actual translation also (otherwise we should check fhtovp 275 1.41 pooka * also, and that's getting a wee bit ridiculous). 276 1.41 pooka */ 277 1.15 martin fid_size = 0; 278 1.41 pooka if ((error = VFS_VPTOFH(vp, NULL, &fid_size)) != E2BIG) { 279 1.26 chs vput(vp); 280 1.25 chs return EOPNOTSUPP; 281 1.1 jmmv } 282 1.1 jmmv 283 1.1 jmmv /* Mark the file system busy. */ 284 1.60 hannken error = vfs_busy(mp); 285 1.25 chs vput(vp); 286 1.1 jmmv if (error != 0) 287 1.25 chs return error; 288 1.48 christos if (nmp == NULL) 289 1.61 ad mutex_enter(mp->mnt_updating); /* mnt_flag */ 290 1.8 yamt netexport_wrlock(); 291 1.5 yamt ne = netexport_lookup(mp); 292 1.5 yamt if (ne == NULL) { 293 1.5 yamt error = init_exports(mp, &ne); 294 1.1 jmmv if (error != 0) { 295 1.25 chs goto out; 296 1.1 jmmv } 297 1.1 jmmv } 298 1.1 jmmv 299 1.5 yamt KASSERT(ne != NULL); 300 1.5 yamt KASSERT(ne->ne_mount == mp); 301 1.5 yamt 302 1.63 hannken if (cmd == NFSSVC_SETEXPORTSLIST) { 303 1.63 hannken if (mel->mel_nexports == 0) 304 1.63 hannken netexport_clear(ne); 305 1.63 hannken else if (mel->mel_nexports == 1) 306 1.63 hannken error = export(ne, &mel->mel_exports[0]); 307 1.63 hannken else { 308 1.63 hannken printf("%s: Cannot set more than one " 309 1.63 hannken "entry at once (unimplemented)\n", __func__); 310 1.63 hannken error = EOPNOTSUPP; 311 1.63 hannken } 312 1.63 hannken } else if (cmd == NFSSVC_REPLACEEXPORTSLIST) { 313 1.12 yamt netexport_clear(ne); 314 1.63 hannken for (i = 0; error == 0 && i < mel->mel_nexports; i++) 315 1.63 hannken error = export(ne, &mel->mel_exports[i]); 316 1.63 hannken } else { 317 1.63 hannken printf("%s: Command %#x not implemented\n", __func__, cmd); 318 1.1 jmmv error = EOPNOTSUPP; 319 1.1 jmmv } 320 1.1 jmmv 321 1.25 chs out: 322 1.8 yamt netexport_wrunlock(); 323 1.48 christos if (nmp == NULL) 324 1.61 ad mutex_exit(mp->mnt_updating); /* mnt_flag */ 325 1.60 hannken vfs_unbusy(mp); 326 1.4 yamt return error; 327 1.1 jmmv } 328 1.1 jmmv 329 1.5 yamt static void 330 1.5 yamt netexport_insert(struct netexport *ne) 331 1.5 yamt { 332 1.5 yamt 333 1.57 christos TAILQ_INSERT_HEAD(&netexport_list, ne, ne_list); 334 1.5 yamt } 335 1.5 yamt 336 1.5 yamt static void 337 1.5 yamt netexport_remove(struct netexport *ne) 338 1.5 yamt { 339 1.5 yamt 340 1.57 christos TAILQ_REMOVE(&netexport_list, ne, ne_list); 341 1.5 yamt } 342 1.5 yamt 343 1.5 yamt static struct netexport * 344 1.5 yamt netexport_lookup(const struct mount *mp) 345 1.5 yamt { 346 1.5 yamt struct netexport *ne; 347 1.5 yamt 348 1.57 christos TAILQ_FOREACH(ne, &netexport_list, ne_list) { 349 1.5 yamt if (ne->ne_mount == mp) { 350 1.5 yamt goto done; 351 1.5 yamt } 352 1.5 yamt } 353 1.5 yamt ne = NULL; 354 1.5 yamt done: 355 1.5 yamt return ne; 356 1.5 yamt } 357 1.5 yamt 358 1.5 yamt static struct netexport * 359 1.5 yamt netexport_lookup_byfsid(const fsid_t *fsid) 360 1.5 yamt { 361 1.5 yamt struct netexport *ne; 362 1.5 yamt 363 1.57 christos TAILQ_FOREACH(ne, &netexport_list, ne_list) { 364 1.5 yamt const struct mount *mp = ne->ne_mount; 365 1.5 yamt 366 1.5 yamt if (mp->mnt_stat.f_fsidx.__fsid_val[0] == fsid->__fsid_val[0] && 367 1.5 yamt mp->mnt_stat.f_fsidx.__fsid_val[1] == fsid->__fsid_val[1]) { 368 1.5 yamt goto done; 369 1.5 yamt } 370 1.5 yamt } 371 1.5 yamt ne = NULL; 372 1.5 yamt done: 373 1.5 yamt 374 1.5 yamt return ne; 375 1.5 yamt } 376 1.5 yamt 377 1.1 jmmv /* 378 1.1 jmmv * Check if the file system specified by the 'mp' mount structure is 379 1.1 jmmv * exported to a client with 'anon' anonymous credentials. The 'mb' 380 1.1 jmmv * argument is an mbuf containing the network address of the client. 381 1.1 jmmv * The return parameters for the export flags for the client are returned 382 1.1 jmmv * in the address specified by 'wh'. 383 1.1 jmmv * 384 1.1 jmmv * This function is used exclusively by the NFS server. It is generally 385 1.53 dholland * invoked before VFS_FHTOVP to validate that a client has access to the 386 1.1 jmmv * file system. 387 1.1 jmmv */ 388 1.5 yamt 389 1.1 jmmv int 390 1.5 yamt netexport_check(const fsid_t *fsid, struct mbuf *mb, struct mount **mpp, 391 1.11 elad int *wh, kauth_cred_t *anon) 392 1.1 jmmv { 393 1.5 yamt struct netexport *ne; 394 1.1 jmmv struct netcred *np; 395 1.1 jmmv 396 1.5 yamt ne = netexport_lookup_byfsid(fsid); 397 1.5 yamt if (ne == NULL) { 398 1.5 yamt return EACCES; 399 1.1 jmmv } 400 1.5 yamt np = netcred_lookup(ne, mb); 401 1.5 yamt if (np == NULL) { 402 1.1 jmmv return EACCES; 403 1.5 yamt } 404 1.1 jmmv 405 1.5 yamt *mpp = ne->ne_mount; 406 1.5 yamt *wh = np->netc_exflags; 407 1.11 elad *anon = np->netc_anon; 408 1.1 jmmv 409 1.5 yamt return 0; 410 1.1 jmmv } 411 1.1 jmmv 412 1.3 jmmv /* 413 1.3 jmmv * Handles legacy export requests. In this case, the export information 414 1.3 jmmv * is hardcoded in a specific place of the mount arguments structure (given 415 1.3 jmmv * in data); the request for an update is given through the fspec field 416 1.3 jmmv * (also in a known location), which must be a null pointer. 417 1.3 jmmv * 418 1.3 jmmv * Returns EJUSTRETURN if the given command was not a export request. 419 1.3 jmmv * Otherwise, returns 0 on success or an appropriate error code otherwise. 420 1.3 jmmv */ 421 1.40 ad static int 422 1.40 ad nfs_export_update_30(struct mount *mp, const char *path, void *data) 423 1.3 jmmv { 424 1.3 jmmv struct mountd_exports_list mel; 425 1.40 ad struct mnt_export_args30 *args; 426 1.3 jmmv 427 1.40 ad args = data; 428 1.3 jmmv mel.mel_path = path; 429 1.3 jmmv 430 1.30 dsl if (args->fspec != NULL) 431 1.3 jmmv return EJUSTRETURN; 432 1.3 jmmv 433 1.30 dsl if (args->eargs.ex_flags & 0x00020000) { 434 1.3 jmmv /* Request to delete exports. The mask above holds the 435 1.3 jmmv * value that used to be in MNT_DELEXPORT. */ 436 1.3 jmmv mel.mel_nexports = 0; 437 1.3 jmmv } else { 438 1.54 dholland /* 439 1.54 dholland * The following code assumes export_args has not 440 1.54 dholland * changed since export_args30, so check that. 441 1.54 dholland */ 442 1.54 dholland __CTASSERT(sizeof(args->eargs) == sizeof(*mel.mel_exports)); 443 1.3 jmmv 444 1.3 jmmv mel.mel_nexports = 1; 445 1.30 dsl mel.mel_exports = (void *)&args->eargs; 446 1.3 jmmv } 447 1.3 jmmv 448 1.63 hannken return mountd_set_exports_list(&mel, curlwp, mp, NFSSVC_SETEXPORTSLIST); 449 1.3 jmmv } 450 1.3 jmmv 451 1.1 jmmv /* 452 1.1 jmmv * INTERNAL FUNCTIONS 453 1.1 jmmv */ 454 1.1 jmmv 455 1.1 jmmv /* 456 1.42 pooka * Initializes NFS exports for the mountpoint given in 'mp'. 457 1.42 pooka * If successful, returns 0 and sets *nep to the address of the new 458 1.42 pooka * netexport item; otherwise returns an appropriate error code 459 1.42 pooka * and *nep remains unmodified. 460 1.1 jmmv */ 461 1.1 jmmv static int 462 1.5 yamt init_exports(struct mount *mp, struct netexport **nep) 463 1.1 jmmv { 464 1.1 jmmv int error; 465 1.1 jmmv struct export_args ea; 466 1.5 yamt struct netexport *ne; 467 1.1 jmmv 468 1.1 jmmv KASSERT(mp != NULL); 469 1.1 jmmv 470 1.1 jmmv /* Ensure that we do not already have this mount point. */ 471 1.5 yamt KASSERT(netexport_lookup(mp) == NULL); 472 1.1 jmmv 473 1.43 pooka ne = kmem_zalloc(sizeof(*ne), KM_SLEEP); 474 1.5 yamt ne->ne_mount = mp; 475 1.1 jmmv 476 1.1 jmmv /* Set the default export entry. Handled internally by export upon 477 1.1 jmmv * first call. */ 478 1.1 jmmv memset(&ea, 0, sizeof(ea)); 479 1.1 jmmv ea.ex_root = -2; 480 1.1 jmmv if (mp->mnt_flag & MNT_RDONLY) 481 1.1 jmmv ea.ex_flags |= MNT_EXRDONLY; 482 1.5 yamt error = export(ne, &ea); 483 1.5 yamt if (error != 0) { 484 1.43 pooka kmem_free(ne, sizeof(*ne)); 485 1.5 yamt } else { 486 1.5 yamt netexport_insert(ne); 487 1.5 yamt *nep = ne; 488 1.1 jmmv } 489 1.1 jmmv 490 1.1 jmmv return error; 491 1.1 jmmv } 492 1.1 jmmv 493 1.1 jmmv /* 494 1.1 jmmv * Build hash lists of net addresses and hang them off the mount point. 495 1.1 jmmv * Called by export() to set up a new entry in the lists of export 496 1.1 jmmv * addresses. 497 1.1 jmmv */ 498 1.1 jmmv static int 499 1.1 jmmv hang_addrlist(struct mount *mp, struct netexport *nep, 500 1.1 jmmv const struct export_args *argp) 501 1.1 jmmv { 502 1.1 jmmv int error, i; 503 1.1 jmmv struct netcred *np, *enp; 504 1.1 jmmv struct radix_node_head *rnh; 505 1.1 jmmv struct sockaddr *saddr, *smask; 506 1.1 jmmv struct domain *dom; 507 1.1 jmmv 508 1.1 jmmv smask = NULL; 509 1.1 jmmv 510 1.1 jmmv if (argp->ex_addrlen == 0) { 511 1.1 jmmv if (mp->mnt_flag & MNT_DEFEXPORTED) 512 1.1 jmmv return EPERM; 513 1.1 jmmv np = &nep->ne_defexported; 514 1.13 yamt KASSERT(np->netc_anon == NULL); 515 1.13 yamt np->netc_anon = kauth_cred_alloc(); 516 1.1 jmmv np->netc_exflags = argp->ex_flags; 517 1.18 pooka kauth_uucred_to_cred(np->netc_anon, &argp->ex_anon); 518 1.1 jmmv mp->mnt_flag |= MNT_DEFEXPORTED; 519 1.1 jmmv return 0; 520 1.1 jmmv } 521 1.1 jmmv 522 1.1 jmmv if (argp->ex_addrlen > MLEN || argp->ex_masklen > MLEN) 523 1.1 jmmv return EINVAL; 524 1.1 jmmv 525 1.1 jmmv i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen; 526 1.5 yamt np = malloc(i, M_NETADDR, M_WAITOK | M_ZERO); 527 1.13 yamt np->netc_anon = kauth_cred_alloc(); 528 1.1 jmmv saddr = (struct sockaddr *)(np + 1); 529 1.5 yamt error = copyin(argp->ex_addr, saddr, argp->ex_addrlen); 530 1.1 jmmv if (error) 531 1.1 jmmv goto out; 532 1.1 jmmv if (saddr->sa_len > argp->ex_addrlen) 533 1.1 jmmv saddr->sa_len = argp->ex_addrlen; 534 1.59 maxv if (sacheck(saddr) == -1) { 535 1.59 maxv error = EINVAL; 536 1.59 maxv goto out; 537 1.59 maxv } 538 1.1 jmmv if (argp->ex_masklen) { 539 1.27 christos smask = (struct sockaddr *)((char *)saddr + argp->ex_addrlen); 540 1.5 yamt error = copyin(argp->ex_mask, smask, argp->ex_masklen); 541 1.1 jmmv if (error) 542 1.1 jmmv goto out; 543 1.1 jmmv if (smask->sa_len > argp->ex_masklen) 544 1.1 jmmv smask->sa_len = argp->ex_masklen; 545 1.59 maxv if (smask->sa_family != saddr->sa_family) { 546 1.59 maxv error = EINVAL; 547 1.59 maxv goto out; 548 1.59 maxv } 549 1.59 maxv if (sacheck(smask) == -1) { 550 1.59 maxv error = EINVAL; 551 1.59 maxv goto out; 552 1.59 maxv } 553 1.1 jmmv } 554 1.1 jmmv i = saddr->sa_family; 555 1.1 jmmv if ((rnh = nep->ne_rtable[i]) == 0) { 556 1.1 jmmv /* 557 1.1 jmmv * Seems silly to initialize every AF when most are not 558 1.53 dholland * used, do so on demand here. 559 1.1 jmmv */ 560 1.1 jmmv DOMAIN_FOREACH(dom) { 561 1.1 jmmv if (dom->dom_family == i && dom->dom_rtattach) { 562 1.50 dyoung rn_inithead((void **)&nep->ne_rtable[i], 563 1.1 jmmv dom->dom_rtoffset); 564 1.1 jmmv break; 565 1.1 jmmv } 566 1.1 jmmv } 567 1.1 jmmv if ((rnh = nep->ne_rtable[i]) == 0) { 568 1.1 jmmv error = ENOBUFS; 569 1.1 jmmv goto out; 570 1.1 jmmv } 571 1.1 jmmv } 572 1.1 jmmv 573 1.1 jmmv enp = (struct netcred *)(*rnh->rnh_addaddr)(saddr, smask, rnh, 574 1.1 jmmv np->netc_rnodes); 575 1.1 jmmv if (enp != np) { 576 1.1 jmmv if (enp == NULL) { 577 1.1 jmmv enp = (struct netcred *)(*rnh->rnh_lookup)(saddr, 578 1.1 jmmv smask, rnh); 579 1.1 jmmv if (enp == NULL) { 580 1.1 jmmv error = EPERM; 581 1.1 jmmv goto out; 582 1.1 jmmv } 583 1.1 jmmv } else 584 1.1 jmmv enp->netc_refcnt++; 585 1.1 jmmv 586 1.1 jmmv goto check; 587 1.1 jmmv } else 588 1.1 jmmv enp->netc_refcnt = 1; 589 1.1 jmmv 590 1.1 jmmv np->netc_exflags = argp->ex_flags; 591 1.18 pooka kauth_uucred_to_cred(np->netc_anon, &argp->ex_anon); 592 1.1 jmmv return 0; 593 1.1 jmmv check: 594 1.1 jmmv if (enp->netc_exflags != argp->ex_flags || 595 1.11 elad kauth_cred_uucmp(enp->netc_anon, &argp->ex_anon) != 0) 596 1.1 jmmv error = EPERM; 597 1.1 jmmv else 598 1.1 jmmv error = 0; 599 1.1 jmmv out: 600 1.13 yamt KASSERT(np->netc_anon != NULL); 601 1.13 yamt kauth_cred_free(np->netc_anon); 602 1.1 jmmv free(np, M_NETADDR); 603 1.1 jmmv return error; 604 1.1 jmmv } 605 1.1 jmmv 606 1.1 jmmv /* 607 1.1 jmmv * Ensure that the address stored in 'sa' is valid. 608 1.1 jmmv * Returns zero on success, otherwise -1. 609 1.1 jmmv */ 610 1.1 jmmv static int 611 1.1 jmmv sacheck(struct sockaddr *sa) 612 1.1 jmmv { 613 1.1 jmmv 614 1.1 jmmv switch (sa->sa_family) { 615 1.1 jmmv case AF_INET: { 616 1.1 jmmv struct sockaddr_in *sin = (struct sockaddr_in *)sa; 617 1.1 jmmv char *p = (char *)sin->sin_zero; 618 1.1 jmmv size_t i; 619 1.1 jmmv 620 1.1 jmmv if (sin->sin_len != sizeof(*sin)) 621 1.1 jmmv return -1; 622 1.1 jmmv if (sin->sin_port != 0) 623 1.1 jmmv return -1; 624 1.1 jmmv for (i = 0; i < sizeof(sin->sin_zero); i++) 625 1.1 jmmv if (*p++ != '\0') 626 1.1 jmmv return -1; 627 1.1 jmmv return 0; 628 1.1 jmmv } 629 1.1 jmmv case AF_INET6: { 630 1.1 jmmv struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 631 1.1 jmmv 632 1.1 jmmv if (sin6->sin6_len != sizeof(*sin6)) 633 1.1 jmmv return -1; 634 1.1 jmmv if (sin6->sin6_port != 0) 635 1.1 jmmv return -1; 636 1.1 jmmv return 0; 637 1.1 jmmv } 638 1.1 jmmv default: 639 1.1 jmmv return -1; 640 1.1 jmmv } 641 1.1 jmmv } 642 1.1 jmmv 643 1.1 jmmv /* 644 1.1 jmmv * Free the netcred object pointed to by the 'rn' radix node. 645 1.1 jmmv * 'w' holds a pointer to the radix tree head. 646 1.1 jmmv */ 647 1.1 jmmv static int 648 1.1 jmmv free_netcred(struct radix_node *rn, void *w) 649 1.1 jmmv { 650 1.1 jmmv struct radix_node_head *rnh = (struct radix_node_head *)w; 651 1.1 jmmv struct netcred *np = (struct netcred *)(void *)rn; 652 1.1 jmmv 653 1.1 jmmv (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh); 654 1.13 yamt if (--(np->netc_refcnt) <= 0) { 655 1.13 yamt KASSERT(np->netc_anon != NULL); 656 1.13 yamt kauth_cred_free(np->netc_anon); 657 1.1 jmmv free(np, M_NETADDR); 658 1.13 yamt } 659 1.1 jmmv return 0; 660 1.1 jmmv } 661 1.1 jmmv 662 1.1 jmmv /* 663 1.1 jmmv * Clears the exports list for a given file system. 664 1.1 jmmv */ 665 1.1 jmmv static void 666 1.12 yamt netexport_clear(struct netexport *ne) 667 1.1 jmmv { 668 1.5 yamt struct radix_node_head *rnh; 669 1.5 yamt struct mount *mp = ne->ne_mount; 670 1.1 jmmv int i; 671 1.1 jmmv 672 1.1 jmmv if (mp->mnt_flag & MNT_EXPUBLIC) { 673 1.1 jmmv setpublicfs(NULL, NULL, NULL); 674 1.1 jmmv mp->mnt_flag &= ~MNT_EXPUBLIC; 675 1.1 jmmv } 676 1.1 jmmv 677 1.1 jmmv for (i = 0; i <= AF_MAX; i++) { 678 1.5 yamt if ((rnh = ne->ne_rtable[i]) != NULL) { 679 1.28 dyoung rn_walktree(rnh, free_netcred, rnh); 680 1.5 yamt free(rnh, M_RTABLE); 681 1.5 yamt ne->ne_rtable[i] = NULL; 682 1.1 jmmv } 683 1.1 jmmv } 684 1.1 jmmv 685 1.13 yamt if ((mp->mnt_flag & MNT_DEFEXPORTED) != 0) { 686 1.13 yamt struct netcred *np = &ne->ne_defexported; 687 1.13 yamt 688 1.13 yamt KASSERT(np->netc_anon != NULL); 689 1.13 yamt kauth_cred_free(np->netc_anon); 690 1.13 yamt np->netc_anon = NULL; 691 1.13 yamt } else { 692 1.13 yamt KASSERT(ne->ne_defexported.netc_anon == NULL); 693 1.13 yamt } 694 1.13 yamt 695 1.1 jmmv mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED); 696 1.1 jmmv } 697 1.1 jmmv 698 1.1 jmmv /* 699 1.1 jmmv * Add a new export entry (described by an export_args structure) to the 700 1.1 jmmv * given file system. 701 1.1 jmmv */ 702 1.1 jmmv static int 703 1.5 yamt export(struct netexport *nep, const struct export_args *argp) 704 1.1 jmmv { 705 1.5 yamt struct mount *mp = nep->ne_mount; 706 1.1 jmmv int error; 707 1.1 jmmv 708 1.1 jmmv if (argp->ex_flags & MNT_EXPORTED) { 709 1.1 jmmv if (argp->ex_flags & MNT_EXPUBLIC) { 710 1.1 jmmv if ((error = setpublicfs(mp, nep, argp)) != 0) 711 1.1 jmmv return error; 712 1.1 jmmv mp->mnt_flag |= MNT_EXPUBLIC; 713 1.1 jmmv } 714 1.1 jmmv if ((error = hang_addrlist(mp, nep, argp)) != 0) 715 1.1 jmmv return error; 716 1.1 jmmv mp->mnt_flag |= MNT_EXPORTED; 717 1.1 jmmv } 718 1.1 jmmv return 0; 719 1.1 jmmv } 720 1.1 jmmv 721 1.1 jmmv /* 722 1.1 jmmv * Set the publicly exported filesystem (WebNFS). Currently, only 723 1.1 jmmv * one public filesystem is possible in the spec (RFC 2054 and 2055) 724 1.1 jmmv */ 725 1.1 jmmv static int 726 1.22 yamt setpublicfs(struct mount *mp, struct netexport *nep, 727 1.1 jmmv const struct export_args *argp) 728 1.1 jmmv { 729 1.1 jmmv char *cp; 730 1.1 jmmv int error; 731 1.1 jmmv struct vnode *rvp; 732 1.15 martin size_t fhsize; 733 1.1 jmmv 734 1.1 jmmv /* 735 1.53 dholland * mp == NULL --> invalidate the current info; the FS is 736 1.1 jmmv * no longer exported. May be called from either export 737 1.1 jmmv * or unmount, so check if it hasn't already been done. 738 1.1 jmmv */ 739 1.1 jmmv if (mp == NULL) { 740 1.1 jmmv if (nfs_pub.np_valid) { 741 1.1 jmmv nfs_pub.np_valid = 0; 742 1.15 martin if (nfs_pub.np_handle != NULL) { 743 1.15 martin free(nfs_pub.np_handle, M_TEMP); 744 1.15 martin nfs_pub.np_handle = NULL; 745 1.15 martin } 746 1.1 jmmv if (nfs_pub.np_index != NULL) { 747 1.44 cegger free(nfs_pub.np_index, M_TEMP); 748 1.1 jmmv nfs_pub.np_index = NULL; 749 1.1 jmmv } 750 1.1 jmmv } 751 1.1 jmmv return 0; 752 1.1 jmmv } 753 1.1 jmmv 754 1.1 jmmv /* 755 1.1 jmmv * Only one allowed at a time. 756 1.1 jmmv */ 757 1.1 jmmv if (nfs_pub.np_valid != 0 && mp != nfs_pub.np_mount) 758 1.1 jmmv return EBUSY; 759 1.1 jmmv 760 1.1 jmmv /* 761 1.1 jmmv * Get real filehandle for root of exported FS. 762 1.1 jmmv */ 763 1.62 ad if ((error = VFS_ROOT(mp, LK_EXCLUSIVE, &rvp))) 764 1.1 jmmv return error; 765 1.1 jmmv 766 1.15 martin fhsize = 0; 767 1.15 martin error = vfs_composefh(rvp, NULL, &fhsize); 768 1.15 martin if (error != E2BIG) 769 1.15 martin return error; 770 1.15 martin nfs_pub.np_handle = malloc(fhsize, M_TEMP, M_NOWAIT); 771 1.15 martin if (nfs_pub.np_handle == NULL) 772 1.15 martin error = ENOMEM; 773 1.15 martin else 774 1.15 martin error = vfs_composefh(rvp, nfs_pub.np_handle, &fhsize); 775 1.14 yamt if (error) 776 1.1 jmmv return error; 777 1.1 jmmv 778 1.1 jmmv vput(rvp); 779 1.1 jmmv 780 1.1 jmmv /* 781 1.1 jmmv * If an indexfile was specified, pull it in. 782 1.1 jmmv */ 783 1.1 jmmv if (argp->ex_indexfile != NULL) { 784 1.51 christos nfs_pub.np_index = malloc(NFS_MAXNAMLEN + 1, M_TEMP, M_WAITOK); 785 1.1 jmmv error = copyinstr(argp->ex_indexfile, nfs_pub.np_index, 786 1.51 christos NFS_MAXNAMLEN, (size_t *)0); 787 1.1 jmmv if (!error) { 788 1.1 jmmv /* 789 1.1 jmmv * Check for illegal filenames. 790 1.1 jmmv */ 791 1.1 jmmv for (cp = nfs_pub.np_index; *cp; cp++) { 792 1.1 jmmv if (*cp == '/') { 793 1.1 jmmv error = EINVAL; 794 1.1 jmmv break; 795 1.1 jmmv } 796 1.1 jmmv } 797 1.1 jmmv } 798 1.1 jmmv if (error) { 799 1.44 cegger free(nfs_pub.np_index, M_TEMP); 800 1.1 jmmv return error; 801 1.1 jmmv } 802 1.1 jmmv } 803 1.1 jmmv 804 1.1 jmmv nfs_pub.np_mount = mp; 805 1.1 jmmv nfs_pub.np_valid = 1; 806 1.1 jmmv return 0; 807 1.1 jmmv } 808 1.1 jmmv 809 1.1 jmmv /* 810 1.53 dholland * Look up an export entry in the exports list that matches the address 811 1.1 jmmv * stored in 'nam'. If no entry is found, the default one is used instead 812 1.1 jmmv * (if available). 813 1.1 jmmv */ 814 1.1 jmmv static struct netcred * 815 1.5 yamt netcred_lookup(struct netexport *ne, struct mbuf *nam) 816 1.1 jmmv { 817 1.1 jmmv struct netcred *np; 818 1.1 jmmv struct radix_node_head *rnh; 819 1.1 jmmv struct sockaddr *saddr; 820 1.1 jmmv 821 1.7 yamt if ((ne->ne_mount->mnt_flag & MNT_EXPORTED) == 0) { 822 1.7 yamt return NULL; 823 1.7 yamt } 824 1.5 yamt 825 1.5 yamt /* 826 1.53 dholland * Look in the export list first. 827 1.5 yamt */ 828 1.1 jmmv np = NULL; 829 1.5 yamt if (nam != NULL) { 830 1.5 yamt saddr = mtod(nam, struct sockaddr *); 831 1.5 yamt rnh = ne->ne_rtable[saddr->sa_family]; 832 1.5 yamt if (rnh != NULL) { 833 1.5 yamt np = (struct netcred *) 834 1.27 christos (*rnh->rnh_matchaddr)((void *)saddr, 835 1.5 yamt rnh); 836 1.5 yamt if (np && np->netc_rnodes->rn_flags & RNF_ROOT) 837 1.5 yamt np = NULL; 838 1.1 jmmv } 839 1.1 jmmv } 840 1.5 yamt /* 841 1.5 yamt * If no address match, use the default if it exists. 842 1.5 yamt */ 843 1.5 yamt if (np == NULL && ne->ne_mount->mnt_flag & MNT_DEFEXPORTED) 844 1.5 yamt np = &ne->ne_defexported; 845 1.5 yamt 846 1.1 jmmv return np; 847 1.1 jmmv } 848 1.8 yamt 849 1.8 yamt void 850 1.8 yamt netexport_rdlock(void) 851 1.8 yamt { 852 1.8 yamt 853 1.29 ad rw_enter(&netexport_lock, RW_READER); 854 1.8 yamt } 855 1.8 yamt 856 1.8 yamt void 857 1.8 yamt netexport_rdunlock(void) 858 1.8 yamt { 859 1.8 yamt 860 1.29 ad rw_exit(&netexport_lock); 861 1.8 yamt } 862 1.8 yamt 863 1.8 yamt static void 864 1.8 yamt netexport_wrlock(void) 865 1.8 yamt { 866 1.8 yamt 867 1.29 ad rw_enter(&netexport_lock, RW_WRITER); 868 1.8 yamt } 869 1.8 yamt 870 1.8 yamt static void 871 1.8 yamt netexport_wrunlock(void) 872 1.8 yamt { 873 1.8 yamt 874 1.29 ad rw_exit(&netexport_lock); 875 1.8 yamt } 876 1.58 christos 877 1.58 christos bool 878 1.58 christos netexport_hasexports(void) 879 1.58 christos { 880 1.58 christos 881 1.58 christos return nfs_pub.np_valid || !TAILQ_EMPTY(&netexport_list); 882 1.58 christos } 883