1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Herb Hasler and Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34static const char copyright[] = 35"@(#) Copyright (c) 1989, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37#endif /*not lint*/ 38 39#if 0 40#ifndef lint 41static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 42#endif /*not lint*/ 43#endif 44 45#include <sys/cdefs.h>
| 1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Herb Hasler and Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34static const char copyright[] = 35"@(#) Copyright (c) 1989, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37#endif /*not lint*/ 38 39#if 0 40#ifndef lint 41static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 42#endif /*not lint*/ 43#endif 44 45#include <sys/cdefs.h>
|
46__FBSDID("$FreeBSD: head/usr.sbin/mountd/mountd.c 150214 2005-09-16 11:24:28Z pjd $");
| 46__FBSDID("$FreeBSD: head/usr.sbin/mountd/mountd.c 158857 2006-05-23 17:10:17Z rodrigc $");
|
47 48#include <sys/param.h> 49#include <sys/mount.h> 50#include <sys/fcntl.h> 51#include <sys/stat.h> 52#include <sys/syslog.h> 53#include <sys/sysctl.h> 54#include <sys/linker.h> 55#include <sys/module.h> 56 57#include <rpc/rpc.h> 58#include <rpc/rpc_com.h> 59#include <rpc/pmap_clnt.h> 60#include <rpc/pmap_prot.h> 61#include <rpcsvc/mount.h> 62#include <nfs/rpcv2.h> 63#include <nfs/nfsproto.h> 64#include <nfsserver/nfs.h>
| 47 48#include <sys/param.h> 49#include <sys/mount.h> 50#include <sys/fcntl.h> 51#include <sys/stat.h> 52#include <sys/syslog.h> 53#include <sys/sysctl.h> 54#include <sys/linker.h> 55#include <sys/module.h> 56 57#include <rpc/rpc.h> 58#include <rpc/rpc_com.h> 59#include <rpc/pmap_clnt.h> 60#include <rpc/pmap_prot.h> 61#include <rpcsvc/mount.h> 62#include <nfs/rpcv2.h> 63#include <nfs/nfsproto.h> 64#include <nfsserver/nfs.h>
|
65#include <ufs/ufs/ufsmount.h> 66#include <fs/msdosfs/msdosfsmount.h> 67#include <fs/ntfs/ntfsmount.h> 68#include <isofs/cd9660/cd9660_mount.h> /* XXX need isofs in include */
| |
69 70#include <arpa/inet.h> 71 72#include <ctype.h> 73#include <err.h> 74#include <errno.h> 75#include <grp.h> 76#include <libutil.h> 77#include <limits.h> 78#include <netdb.h> 79#include <pwd.h> 80#include <signal.h> 81#include <stdio.h> 82#include <stdlib.h> 83#include <string.h> 84#include <unistd.h> 85#include "pathnames.h"
| 65 66#include <arpa/inet.h> 67 68#include <ctype.h> 69#include <err.h> 70#include <errno.h> 71#include <grp.h> 72#include <libutil.h> 73#include <limits.h> 74#include <netdb.h> 75#include <pwd.h> 76#include <signal.h> 77#include <stdio.h> 78#include <stdlib.h> 79#include <string.h> 80#include <unistd.h> 81#include "pathnames.h"
|
| 82#include "mntopts.h"
|
86 87#ifdef DEBUG 88#include <stdarg.h> 89#endif 90 91/* 92 * Structures for keeping the mount list and export list 93 */ 94struct mountlist { 95 struct mountlist *ml_next; 96 char ml_host[RPCMNT_NAMELEN+1]; 97 char ml_dirp[RPCMNT_PATHLEN+1]; 98}; 99 100struct dirlist { 101 struct dirlist *dp_left; 102 struct dirlist *dp_right; 103 int dp_flag; 104 struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 105 char dp_dirp[1]; /* Actually malloc'd to size of dir */ 106}; 107/* dp_flag bits */ 108#define DP_DEFSET 0x1 109#define DP_HOSTSET 0x2 110 111struct exportlist { 112 struct exportlist *ex_next; 113 struct dirlist *ex_dirl; 114 struct dirlist *ex_defdir; 115 int ex_flag; 116 fsid_t ex_fs; 117 char *ex_fsdir; 118 char *ex_indexfile; 119}; 120/* ex_flag bits */ 121#define EX_LINKED 0x1 122 123struct netmsk { 124 struct sockaddr_storage nt_net; 125 struct sockaddr_storage nt_mask; 126 char *nt_name; 127}; 128 129union grouptypes { 130 struct addrinfo *gt_addrinfo; 131 struct netmsk gt_net; 132}; 133 134struct grouplist { 135 int gr_type; 136 union grouptypes gr_ptr; 137 struct grouplist *gr_next; 138}; 139/* Group types */ 140#define GT_NULL 0x0 141#define GT_HOST 0x1 142#define GT_NET 0x2 143#define GT_DEFAULT 0x3 144#define GT_IGNORE 0x5 145 146struct hostlist { 147 int ht_flag; /* Uses DP_xx bits */ 148 struct grouplist *ht_grp; 149 struct hostlist *ht_next; 150}; 151 152struct fhreturn { 153 int fhr_flag; 154 int fhr_vers; 155 nfsfh_t fhr_fh; 156}; 157 158/* Global defs */ 159char *add_expdir(struct dirlist **, char *, int); 160void add_dlist(struct dirlist **, struct dirlist *, 161 struct grouplist *, int); 162void add_mlist(char *, char *); 163int check_dirpath(char *); 164int check_options(struct dirlist *); 165int checkmask(struct sockaddr *sa); 166int chk_host(struct dirlist *, struct sockaddr *, int *, int *); 167void del_mlist(char *hostp, char *dirp); 168struct dirlist *dirp_search(struct dirlist *, char *); 169int do_mount(struct exportlist *, struct grouplist *, int, 170 struct xucred *, char *, int, struct statfs *); 171int do_opt(char **, char **, struct exportlist *, struct grouplist *, 172 int *, int *, struct xucred *); 173struct exportlist *ex_search(fsid_t *); 174struct exportlist *get_exp(void); 175void free_dir(struct dirlist *); 176void free_exp(struct exportlist *); 177void free_grp(struct grouplist *); 178void free_host(struct hostlist *); 179void get_exportlist(void); 180int get_host(char *, struct grouplist *, struct grouplist *); 181struct hostlist *get_ht(void); 182int get_line(void); 183void get_mountlist(void); 184int get_net(char *, struct netmsk *, int); 185void getexp_err(struct exportlist *, struct grouplist *); 186struct grouplist *get_grp(void); 187void hang_dirp(struct dirlist *, struct grouplist *, 188 struct exportlist *, int); 189void huphandler(int sig); 190int makemask(struct sockaddr_storage *ssp, int bitlen); 191void mntsrv(struct svc_req *, SVCXPRT *); 192void nextfield(char **, char **); 193void out_of_mem(void); 194void parsecred(char *, struct xucred *); 195int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 196void *sa_rawaddr(struct sockaddr *sa, int *nbytes); 197int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 198 struct sockaddr *samask); 199int scan_tree(struct dirlist *, struct sockaddr *); 200static void usage(void); 201int xdr_dir(XDR *, char *); 202int xdr_explist(XDR *, caddr_t); 203int xdr_explist_brief(XDR *, caddr_t); 204int xdr_fhs(XDR *, caddr_t); 205int xdr_mlist(XDR *, caddr_t); 206void terminate(int); 207 208struct exportlist *exphead; 209struct mountlist *mlhead; 210struct grouplist *grphead; 211char exname[MAXPATHLEN]; 212struct xucred def_anon = { 213 XUCRED_VERSION, 214 (uid_t)-2, 215 1, 216 { (gid_t)-2 }, 217 NULL 218}; 219int force_v2 = 0; 220int resvport_only = 1; 221int dir_only = 1; 222int dolog = 0; 223int got_sighup = 0; 224 225int opt_flags; 226static int have_v6 = 1; 227 228struct pidfh *pfh = NULL; 229/* Bits for opt_flags above */ 230#define OP_MAPROOT 0x01 231#define OP_MAPALL 0x02 232/* 0x4 free */ 233#define OP_MASK 0x08 234#define OP_NET 0x10 235#define OP_ALLDIRS 0x40 236#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 237#define OP_QUIET 0x100 238#define OP_MASKLEN 0x200 239 240#ifdef DEBUG 241int debug = 1; 242void SYSLOG(int, const char *, ...) __printflike(2, 3); 243#define syslog SYSLOG 244#else 245int debug = 0; 246#endif 247 248/* 249 * Mountd server for NFS mount protocol as described in: 250 * NFS: Network File System Protocol Specification, RFC1094, Appendix A 251 * The optional arguments are the exports file name 252 * default: _PATH_EXPORTS 253 * and "-n" to allow nonroot mount. 254 */ 255int 256main(argc, argv) 257 int argc; 258 char **argv; 259{ 260 fd_set readfds; 261 struct sockaddr_in sin; 262 struct sockaddr_in6 sin6; 263 char *endptr; 264 SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; 265 struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 266 pid_t otherpid; 267 int udpsock, tcpsock, udp6sock, tcp6sock; 268 int xcreated = 0, s; 269 int maxrec = RPC_MAXDATASIZE; 270 int one = 1; 271 int c, r; 272 in_port_t svcport = 0; 273 274 udp6conf = tcp6conf = NULL; 275 udp6sock = tcp6sock = 0; 276 277 /* Check that another mountd isn't already running. */ 278 pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 279 if (pfh == NULL) { 280 if (errno == EEXIST) 281 errx(1, "mountd already running, pid: %d.", otherpid); 282 warn("cannot open or create pidfile"); 283 } 284 285 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 286 if (s < 0) 287 have_v6 = 0; 288 else 289 close(s); 290 if (modfind("nfsserver") < 0) { 291 /* Not present in kernel, try loading it */ 292 if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 293 errx(1, "NFS server is not available or loadable"); 294 } 295 296 while ((c = getopt(argc, argv, "2dlnp:r")) != -1) 297 switch (c) { 298 case '2': 299 force_v2 = 1; 300 break; 301 case 'n': 302 resvport_only = 0; 303 break; 304 case 'r': 305 dir_only = 0; 306 break; 307 case 'd': 308 debug = debug ? 0 : 1; 309 break; 310 case 'l': 311 dolog = 1; 312 break; 313 case 'p': 314 endptr = NULL; 315 svcport = (in_port_t)strtoul(optarg, &endptr, 10); 316 if (endptr == NULL || *endptr != '\0' || 317 svcport == 0 || svcport >= IPPORT_MAX) 318 usage(); 319 break; 320 default: 321 usage(); 322 }; 323 argc -= optind; 324 argv += optind; 325 grphead = (struct grouplist *)NULL; 326 exphead = (struct exportlist *)NULL; 327 mlhead = (struct mountlist *)NULL; 328 if (argc == 1) { 329 strncpy(exname, *argv, MAXPATHLEN-1); 330 exname[MAXPATHLEN-1] = '\0'; 331 } else 332 strcpy(exname, _PATH_EXPORTS); 333 openlog("mountd", LOG_PID, LOG_DAEMON); 334 if (debug) 335 warnx("getting export list"); 336 get_exportlist(); 337 if (debug) 338 warnx("getting mount list"); 339 get_mountlist(); 340 if (debug) 341 warnx("here we go"); 342 if (debug == 0) { 343 daemon(0, 0); 344 signal(SIGINT, SIG_IGN); 345 signal(SIGQUIT, SIG_IGN); 346 } 347 signal(SIGHUP, huphandler); 348 signal(SIGTERM, terminate); 349 350 pidfile_write(pfh); 351 352 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 353 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 354 udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 355 tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 356 udpconf = getnetconfigent("udp"); 357 tcpconf = getnetconfigent("tcp"); 358 359 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 360 361 if (!have_v6) 362 goto skip_v6; 363 udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 364 tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 365 /* 366 * We're doing host-based access checks here, so don't allow 367 * v4-in-v6 to confuse things. The kernel will disable it 368 * by default on NFS sockets too. 369 */ 370 if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6, 371 IPV6_V6ONLY, &one, sizeof one) < 0) { 372 syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 373 exit(1); 374 } 375 if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6, 376 IPV6_V6ONLY, &one, sizeof one) < 0) { 377 syslog(LOG_ERR, "can't disable v4-in-v6 on TCP socket"); 378 exit(1); 379 } 380 udp6conf = getnetconfigent("udp6"); 381 tcp6conf = getnetconfigent("tcp6"); 382 383skip_v6: 384 if (!resvport_only) { 385 if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 386 &resvport_only, sizeof(resvport_only)) != 0 && 387 errno != ENOENT) { 388 syslog(LOG_ERR, "sysctl: %m"); 389 exit(1); 390 } 391 } 392 if (svcport != 0) { 393 bzero(&sin, sizeof(struct sockaddr_in)); 394 sin.sin_len = sizeof(struct sockaddr_in); 395 sin.sin_family = AF_INET; 396 sin.sin_port = htons(svcport); 397 398 bzero(&sin6, sizeof(struct sockaddr_in6)); 399 sin6.sin6_len = sizeof(struct sockaddr_in6); 400 sin6.sin6_family = AF_INET6; 401 sin6.sin6_port = htons(svcport); 402 } 403 if (udpsock != -1 && udpconf != NULL) { 404 if (svcport != 0) { 405 r = bindresvport(udpsock, &sin); 406 if (r != 0) { 407 syslog(LOG_ERR, "bindresvport: %m"); 408 exit(1); 409 } 410 } else 411 (void)bindresvport(udpsock, NULL); 412 udptransp = svc_dg_create(udpsock, 0, 0); 413 if (udptransp != NULL) { 414 if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, 415 mntsrv, udpconf)) 416 syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service"); 417 else 418 xcreated++; 419 if (!force_v2) { 420 if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3, 421 mntsrv, udpconf)) 422 syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service"); 423 else 424 xcreated++; 425 } 426 } else 427 syslog(LOG_WARNING, "can't create UDP services"); 428 429 } 430 if (tcpsock != -1 && tcpconf != NULL) { 431 if (svcport != 0) { 432 r = bindresvport(tcpsock, &sin); 433 if (r != 0) { 434 syslog(LOG_ERR, "bindresvport: %m"); 435 exit(1); 436 } 437 } else 438 (void)bindresvport(tcpsock, NULL); 439 listen(tcpsock, SOMAXCONN); 440 tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 441 if (tcptransp != NULL) { 442 if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1, 443 mntsrv, tcpconf)) 444 syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service"); 445 else 446 xcreated++; 447 if (!force_v2) { 448 if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3, 449 mntsrv, tcpconf)) 450 syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service"); 451 else 452 xcreated++; 453 } 454 } else 455 syslog(LOG_WARNING, "can't create TCP service"); 456 457 } 458 if (have_v6 && udp6sock != -1 && udp6conf != NULL) { 459 if (svcport != 0) { 460 r = bindresvport_sa(udp6sock, 461 (struct sockaddr *)&sin6); 462 if (r != 0) { 463 syslog(LOG_ERR, "bindresvport_sa: %m"); 464 exit(1); 465 } 466 } else 467 (void)bindresvport_sa(udp6sock, NULL); 468 udp6transp = svc_dg_create(udp6sock, 0, 0); 469 if (udp6transp != NULL) { 470 if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, 471 mntsrv, udp6conf)) 472 syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service"); 473 else 474 xcreated++; 475 if (!force_v2) { 476 if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3, 477 mntsrv, udp6conf)) 478 syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service"); 479 else 480 xcreated++; 481 } 482 } else 483 syslog(LOG_WARNING, "can't create UDP6 service"); 484 485 } 486 if (have_v6 && tcp6sock != -1 && tcp6conf != NULL) { 487 if (svcport != 0) { 488 r = bindresvport_sa(tcp6sock, 489 (struct sockaddr *)&sin6); 490 if (r != 0) { 491 syslog(LOG_ERR, "bindresvport_sa: %m"); 492 exit(1); 493 } 494 } else 495 (void)bindresvport_sa(tcp6sock, NULL); 496 listen(tcp6sock, SOMAXCONN); 497 tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 498 if (tcp6transp != NULL) { 499 if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1, 500 mntsrv, tcp6conf)) 501 syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service"); 502 else 503 xcreated++; 504 if (!force_v2) { 505 if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3, 506 mntsrv, tcp6conf)) 507 syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service"); 508 else 509 xcreated++; 510 } 511 } else 512 syslog(LOG_WARNING, "can't create TCP6 service"); 513 514 } 515 if (xcreated == 0) { 516 syslog(LOG_ERR, "could not create any services"); 517 exit(1); 518 } 519 520 /* Expand svc_run() here so that we can call get_exportlist(). */ 521 for (;;) { 522 if (got_sighup) { 523 get_exportlist(); 524 got_sighup = 0; 525 } 526 readfds = svc_fdset; 527 switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 528 case -1: 529 if (errno == EINTR) 530 continue; 531 syslog(LOG_ERR, "mountd died: select: %m"); 532 exit(1); 533 case 0: 534 continue; 535 default: 536 svc_getreqset(&readfds); 537 } 538 } 539} 540 541static void 542usage() 543{ 544 fprintf(stderr, 545 "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] " 546 "[export_file]\n"); 547 exit(1); 548} 549 550/* 551 * The mount rpc service 552 */ 553void 554mntsrv(rqstp, transp) 555 struct svc_req *rqstp; 556 SVCXPRT *transp; 557{ 558 struct exportlist *ep; 559 struct dirlist *dp; 560 struct fhreturn fhr; 561 struct stat stb; 562 struct statfs fsb; 563 char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 564 int lookup_failed = 1; 565 struct sockaddr *saddr; 566 u_short sport; 567 char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 568 int bad = 0, defset, hostset; 569 sigset_t sighup_mask; 570 571 sigemptyset(&sighup_mask); 572 sigaddset(&sighup_mask, SIGHUP); 573 saddr = svc_getrpccaller(transp)->buf; 574 switch (saddr->sa_family) { 575 case AF_INET6: 576 sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 577 break; 578 case AF_INET: 579 sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 580 break; 581 default: 582 syslog(LOG_ERR, "request from unknown address family"); 583 return; 584 } 585 lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 586 NULL, 0, 0); 587 getnameinfo(saddr, saddr->sa_len, numerichost, 588 sizeof numerichost, NULL, 0, NI_NUMERICHOST); 589 switch (rqstp->rq_proc) { 590 case NULLPROC: 591 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 592 syslog(LOG_ERR, "can't send reply"); 593 return; 594 case RPCMNT_MOUNT: 595 if (sport >= IPPORT_RESERVED && resvport_only) { 596 syslog(LOG_NOTICE, 597 "mount request from %s from unprivileged port", 598 numerichost); 599 svcerr_weakauth(transp); 600 return; 601 } 602 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 603 syslog(LOG_NOTICE, "undecodable mount request from %s", 604 numerichost); 605 svcerr_decode(transp); 606 return; 607 } 608 609 /* 610 * Get the real pathname and make sure it is a directory 611 * or a regular file if the -r option was specified 612 * and it exists. 613 */ 614 if (realpath(rpcpath, dirpath) == NULL || 615 stat(dirpath, &stb) < 0 || 616 (!S_ISDIR(stb.st_mode) && 617 (dir_only || !S_ISREG(stb.st_mode))) || 618 statfs(dirpath, &fsb) < 0) { 619 chdir("/"); /* Just in case realpath doesn't */ 620 syslog(LOG_NOTICE, 621 "mount request from %s for non existent path %s", 622 numerichost, dirpath); 623 if (debug) 624 warnx("stat failed on %s", dirpath); 625 bad = ENOENT; /* We will send error reply later */ 626 } 627 628 /* Check in the exports list */ 629 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 630 ep = ex_search(&fsb.f_fsid); 631 hostset = defset = 0; 632 if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 633 ((dp = dirp_search(ep->ex_dirl, dirpath)) && 634 chk_host(dp, saddr, &defset, &hostset)) || 635 (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 636 scan_tree(ep->ex_dirl, saddr) == 0))) { 637 if (bad) { 638 if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 639 (caddr_t)&bad)) 640 syslog(LOG_ERR, "can't send reply"); 641 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 642 return; 643 } 644 if (hostset & DP_HOSTSET) 645 fhr.fhr_flag = hostset; 646 else 647 fhr.fhr_flag = defset; 648 fhr.fhr_vers = rqstp->rq_vers; 649 /* Get the file handle */ 650 memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 651 if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 652 bad = errno; 653 syslog(LOG_ERR, "can't get fh for %s", dirpath); 654 if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 655 (caddr_t)&bad)) 656 syslog(LOG_ERR, "can't send reply"); 657 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 658 return; 659 } 660 if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 661 (caddr_t)&fhr)) 662 syslog(LOG_ERR, "can't send reply"); 663 if (!lookup_failed) 664 add_mlist(host, dirpath); 665 else 666 add_mlist(numerichost, dirpath); 667 if (debug) 668 warnx("mount successful"); 669 if (dolog) 670 syslog(LOG_NOTICE, 671 "mount request succeeded from %s for %s", 672 numerichost, dirpath); 673 } else { 674 bad = EACCES; 675 syslog(LOG_NOTICE, 676 "mount request denied from %s for %s", 677 numerichost, dirpath); 678 } 679 680 if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 681 (caddr_t)&bad)) 682 syslog(LOG_ERR, "can't send reply"); 683 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 684 return; 685 case RPCMNT_DUMP: 686 if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 687 syslog(LOG_ERR, "can't send reply"); 688 else if (dolog) 689 syslog(LOG_NOTICE, 690 "dump request succeeded from %s", 691 numerichost); 692 return; 693 case RPCMNT_UMOUNT: 694 if (sport >= IPPORT_RESERVED && resvport_only) { 695 syslog(LOG_NOTICE, 696 "umount request from %s from unprivileged port", 697 numerichost); 698 svcerr_weakauth(transp); 699 return; 700 } 701 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 702 syslog(LOG_NOTICE, "undecodable umount request from %s", 703 numerichost); 704 svcerr_decode(transp); 705 return; 706 } 707 if (realpath(rpcpath, dirpath) == NULL) { 708 syslog(LOG_NOTICE, "umount request from %s " 709 "for non existent path %s", 710 numerichost, dirpath); 711 } 712 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 713 syslog(LOG_ERR, "can't send reply"); 714 if (!lookup_failed) 715 del_mlist(host, dirpath); 716 del_mlist(numerichost, dirpath); 717 if (dolog) 718 syslog(LOG_NOTICE, 719 "umount request succeeded from %s for %s", 720 numerichost, dirpath); 721 return; 722 case RPCMNT_UMNTALL: 723 if (sport >= IPPORT_RESERVED && resvport_only) { 724 syslog(LOG_NOTICE, 725 "umountall request from %s from unprivileged port", 726 numerichost); 727 svcerr_weakauth(transp); 728 return; 729 } 730 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 731 syslog(LOG_ERR, "can't send reply"); 732 if (!lookup_failed) 733 del_mlist(host, NULL); 734 del_mlist(numerichost, NULL); 735 if (dolog) 736 syslog(LOG_NOTICE, 737 "umountall request succeeded from %s", 738 numerichost); 739 return; 740 case RPCMNT_EXPORT: 741 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 742 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 743 (caddr_t)NULL)) 744 syslog(LOG_ERR, "can't send reply"); 745 if (dolog) 746 syslog(LOG_NOTICE, 747 "export request succeeded from %s", 748 numerichost); 749 return; 750 default: 751 svcerr_noproc(transp); 752 return; 753 } 754} 755 756/* 757 * Xdr conversion for a dirpath string 758 */ 759int 760xdr_dir(xdrsp, dirp) 761 XDR *xdrsp; 762 char *dirp; 763{ 764 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 765} 766 767/* 768 * Xdr routine to generate file handle reply 769 */ 770int 771xdr_fhs(xdrsp, cp) 772 XDR *xdrsp; 773 caddr_t cp; 774{ 775 struct fhreturn *fhrp = (struct fhreturn *)cp; 776 u_long ok = 0, len, auth; 777 778 if (!xdr_long(xdrsp, &ok)) 779 return (0); 780 switch (fhrp->fhr_vers) { 781 case 1: 782 return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 783 case 3: 784 len = NFSX_V3FH; 785 if (!xdr_long(xdrsp, &len)) 786 return (0); 787 if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 788 return (0); 789 auth = RPCAUTH_UNIX; 790 len = 1; 791 if (!xdr_long(xdrsp, &len)) 792 return (0); 793 return (xdr_long(xdrsp, &auth)); 794 }; 795 return (0); 796} 797 798int 799xdr_mlist(xdrsp, cp) 800 XDR *xdrsp; 801 caddr_t cp; 802{ 803 struct mountlist *mlp; 804 int true = 1; 805 int false = 0; 806 char *strp; 807 808 mlp = mlhead; 809 while (mlp) { 810 if (!xdr_bool(xdrsp, &true)) 811 return (0); 812 strp = &mlp->ml_host[0]; 813 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 814 return (0); 815 strp = &mlp->ml_dirp[0]; 816 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 817 return (0); 818 mlp = mlp->ml_next; 819 } 820 if (!xdr_bool(xdrsp, &false)) 821 return (0); 822 return (1); 823} 824 825/* 826 * Xdr conversion for export list 827 */ 828int 829xdr_explist_common(xdrsp, cp, brief) 830 XDR *xdrsp; 831 caddr_t cp; 832 int brief; 833{ 834 struct exportlist *ep; 835 int false = 0; 836 int putdef; 837 sigset_t sighup_mask; 838 839 sigemptyset(&sighup_mask); 840 sigaddset(&sighup_mask, SIGHUP); 841 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 842 ep = exphead; 843 while (ep) { 844 putdef = 0; 845 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 846 &putdef, brief)) 847 goto errout; 848 if (ep->ex_defdir && putdef == 0 && 849 put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 850 &putdef, brief)) 851 goto errout; 852 ep = ep->ex_next; 853 } 854 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 855 if (!xdr_bool(xdrsp, &false)) 856 return (0); 857 return (1); 858errout: 859 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 860 return (0); 861} 862 863/* 864 * Called from xdr_explist() to traverse the tree and export the 865 * directory paths. 866 */ 867int 868put_exlist(dp, xdrsp, adp, putdefp, brief) 869 struct dirlist *dp; 870 XDR *xdrsp; 871 struct dirlist *adp; 872 int *putdefp; 873 int brief; 874{ 875 struct grouplist *grp; 876 struct hostlist *hp; 877 int true = 1; 878 int false = 0; 879 int gotalldir = 0; 880 char *strp; 881 882 if (dp) { 883 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 884 return (1); 885 if (!xdr_bool(xdrsp, &true)) 886 return (1); 887 strp = dp->dp_dirp; 888 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 889 return (1); 890 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 891 gotalldir = 1; 892 *putdefp = 1; 893 } 894 if (brief) { 895 if (!xdr_bool(xdrsp, &true)) 896 return (1); 897 strp = "(...)"; 898 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 899 return (1); 900 } else if ((dp->dp_flag & DP_DEFSET) == 0 && 901 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 902 hp = dp->dp_hosts; 903 while (hp) { 904 grp = hp->ht_grp; 905 if (grp->gr_type == GT_HOST) { 906 if (!xdr_bool(xdrsp, &true)) 907 return (1); 908 strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 909 if (!xdr_string(xdrsp, &strp, 910 RPCMNT_NAMELEN)) 911 return (1); 912 } else if (grp->gr_type == GT_NET) { 913 if (!xdr_bool(xdrsp, &true)) 914 return (1); 915 strp = grp->gr_ptr.gt_net.nt_name; 916 if (!xdr_string(xdrsp, &strp, 917 RPCMNT_NAMELEN)) 918 return (1); 919 } 920 hp = hp->ht_next; 921 if (gotalldir && hp == (struct hostlist *)NULL) { 922 hp = adp->dp_hosts; 923 gotalldir = 0; 924 } 925 } 926 } 927 if (!xdr_bool(xdrsp, &false)) 928 return (1); 929 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 930 return (1); 931 } 932 return (0); 933} 934 935int 936xdr_explist(xdrsp, cp) 937 XDR *xdrsp; 938 caddr_t cp; 939{ 940 941 return xdr_explist_common(xdrsp, cp, 0); 942} 943 944int 945xdr_explist_brief(xdrsp, cp) 946 XDR *xdrsp; 947 caddr_t cp; 948{ 949 950 return xdr_explist_common(xdrsp, cp, 1); 951} 952 953char *line; 954int linesize; 955FILE *exp_file; 956 957/* 958 * Get the export list 959 */ 960void 961get_exportlist() 962{ 963 struct exportlist *ep, *ep2; 964 struct grouplist *grp, *tgrp; 965 struct exportlist **epp;
| 83 84#ifdef DEBUG 85#include <stdarg.h> 86#endif 87 88/* 89 * Structures for keeping the mount list and export list 90 */ 91struct mountlist { 92 struct mountlist *ml_next; 93 char ml_host[RPCMNT_NAMELEN+1]; 94 char ml_dirp[RPCMNT_PATHLEN+1]; 95}; 96 97struct dirlist { 98 struct dirlist *dp_left; 99 struct dirlist *dp_right; 100 int dp_flag; 101 struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 102 char dp_dirp[1]; /* Actually malloc'd to size of dir */ 103}; 104/* dp_flag bits */ 105#define DP_DEFSET 0x1 106#define DP_HOSTSET 0x2 107 108struct exportlist { 109 struct exportlist *ex_next; 110 struct dirlist *ex_dirl; 111 struct dirlist *ex_defdir; 112 int ex_flag; 113 fsid_t ex_fs; 114 char *ex_fsdir; 115 char *ex_indexfile; 116}; 117/* ex_flag bits */ 118#define EX_LINKED 0x1 119 120struct netmsk { 121 struct sockaddr_storage nt_net; 122 struct sockaddr_storage nt_mask; 123 char *nt_name; 124}; 125 126union grouptypes { 127 struct addrinfo *gt_addrinfo; 128 struct netmsk gt_net; 129}; 130 131struct grouplist { 132 int gr_type; 133 union grouptypes gr_ptr; 134 struct grouplist *gr_next; 135}; 136/* Group types */ 137#define GT_NULL 0x0 138#define GT_HOST 0x1 139#define GT_NET 0x2 140#define GT_DEFAULT 0x3 141#define GT_IGNORE 0x5 142 143struct hostlist { 144 int ht_flag; /* Uses DP_xx bits */ 145 struct grouplist *ht_grp; 146 struct hostlist *ht_next; 147}; 148 149struct fhreturn { 150 int fhr_flag; 151 int fhr_vers; 152 nfsfh_t fhr_fh; 153}; 154 155/* Global defs */ 156char *add_expdir(struct dirlist **, char *, int); 157void add_dlist(struct dirlist **, struct dirlist *, 158 struct grouplist *, int); 159void add_mlist(char *, char *); 160int check_dirpath(char *); 161int check_options(struct dirlist *); 162int checkmask(struct sockaddr *sa); 163int chk_host(struct dirlist *, struct sockaddr *, int *, int *); 164void del_mlist(char *hostp, char *dirp); 165struct dirlist *dirp_search(struct dirlist *, char *); 166int do_mount(struct exportlist *, struct grouplist *, int, 167 struct xucred *, char *, int, struct statfs *); 168int do_opt(char **, char **, struct exportlist *, struct grouplist *, 169 int *, int *, struct xucred *); 170struct exportlist *ex_search(fsid_t *); 171struct exportlist *get_exp(void); 172void free_dir(struct dirlist *); 173void free_exp(struct exportlist *); 174void free_grp(struct grouplist *); 175void free_host(struct hostlist *); 176void get_exportlist(void); 177int get_host(char *, struct grouplist *, struct grouplist *); 178struct hostlist *get_ht(void); 179int get_line(void); 180void get_mountlist(void); 181int get_net(char *, struct netmsk *, int); 182void getexp_err(struct exportlist *, struct grouplist *); 183struct grouplist *get_grp(void); 184void hang_dirp(struct dirlist *, struct grouplist *, 185 struct exportlist *, int); 186void huphandler(int sig); 187int makemask(struct sockaddr_storage *ssp, int bitlen); 188void mntsrv(struct svc_req *, SVCXPRT *); 189void nextfield(char **, char **); 190void out_of_mem(void); 191void parsecred(char *, struct xucred *); 192int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 193void *sa_rawaddr(struct sockaddr *sa, int *nbytes); 194int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 195 struct sockaddr *samask); 196int scan_tree(struct dirlist *, struct sockaddr *); 197static void usage(void); 198int xdr_dir(XDR *, char *); 199int xdr_explist(XDR *, caddr_t); 200int xdr_explist_brief(XDR *, caddr_t); 201int xdr_fhs(XDR *, caddr_t); 202int xdr_mlist(XDR *, caddr_t); 203void terminate(int); 204 205struct exportlist *exphead; 206struct mountlist *mlhead; 207struct grouplist *grphead; 208char exname[MAXPATHLEN]; 209struct xucred def_anon = { 210 XUCRED_VERSION, 211 (uid_t)-2, 212 1, 213 { (gid_t)-2 }, 214 NULL 215}; 216int force_v2 = 0; 217int resvport_only = 1; 218int dir_only = 1; 219int dolog = 0; 220int got_sighup = 0; 221 222int opt_flags; 223static int have_v6 = 1; 224 225struct pidfh *pfh = NULL; 226/* Bits for opt_flags above */ 227#define OP_MAPROOT 0x01 228#define OP_MAPALL 0x02 229/* 0x4 free */ 230#define OP_MASK 0x08 231#define OP_NET 0x10 232#define OP_ALLDIRS 0x40 233#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 234#define OP_QUIET 0x100 235#define OP_MASKLEN 0x200 236 237#ifdef DEBUG 238int debug = 1; 239void SYSLOG(int, const char *, ...) __printflike(2, 3); 240#define syslog SYSLOG 241#else 242int debug = 0; 243#endif 244 245/* 246 * Mountd server for NFS mount protocol as described in: 247 * NFS: Network File System Protocol Specification, RFC1094, Appendix A 248 * The optional arguments are the exports file name 249 * default: _PATH_EXPORTS 250 * and "-n" to allow nonroot mount. 251 */ 252int 253main(argc, argv) 254 int argc; 255 char **argv; 256{ 257 fd_set readfds; 258 struct sockaddr_in sin; 259 struct sockaddr_in6 sin6; 260 char *endptr; 261 SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; 262 struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 263 pid_t otherpid; 264 int udpsock, tcpsock, udp6sock, tcp6sock; 265 int xcreated = 0, s; 266 int maxrec = RPC_MAXDATASIZE; 267 int one = 1; 268 int c, r; 269 in_port_t svcport = 0; 270 271 udp6conf = tcp6conf = NULL; 272 udp6sock = tcp6sock = 0; 273 274 /* Check that another mountd isn't already running. */ 275 pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 276 if (pfh == NULL) { 277 if (errno == EEXIST) 278 errx(1, "mountd already running, pid: %d.", otherpid); 279 warn("cannot open or create pidfile"); 280 } 281 282 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 283 if (s < 0) 284 have_v6 = 0; 285 else 286 close(s); 287 if (modfind("nfsserver") < 0) { 288 /* Not present in kernel, try loading it */ 289 if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 290 errx(1, "NFS server is not available or loadable"); 291 } 292 293 while ((c = getopt(argc, argv, "2dlnp:r")) != -1) 294 switch (c) { 295 case '2': 296 force_v2 = 1; 297 break; 298 case 'n': 299 resvport_only = 0; 300 break; 301 case 'r': 302 dir_only = 0; 303 break; 304 case 'd': 305 debug = debug ? 0 : 1; 306 break; 307 case 'l': 308 dolog = 1; 309 break; 310 case 'p': 311 endptr = NULL; 312 svcport = (in_port_t)strtoul(optarg, &endptr, 10); 313 if (endptr == NULL || *endptr != '\0' || 314 svcport == 0 || svcport >= IPPORT_MAX) 315 usage(); 316 break; 317 default: 318 usage(); 319 }; 320 argc -= optind; 321 argv += optind; 322 grphead = (struct grouplist *)NULL; 323 exphead = (struct exportlist *)NULL; 324 mlhead = (struct mountlist *)NULL; 325 if (argc == 1) { 326 strncpy(exname, *argv, MAXPATHLEN-1); 327 exname[MAXPATHLEN-1] = '\0'; 328 } else 329 strcpy(exname, _PATH_EXPORTS); 330 openlog("mountd", LOG_PID, LOG_DAEMON); 331 if (debug) 332 warnx("getting export list"); 333 get_exportlist(); 334 if (debug) 335 warnx("getting mount list"); 336 get_mountlist(); 337 if (debug) 338 warnx("here we go"); 339 if (debug == 0) { 340 daemon(0, 0); 341 signal(SIGINT, SIG_IGN); 342 signal(SIGQUIT, SIG_IGN); 343 } 344 signal(SIGHUP, huphandler); 345 signal(SIGTERM, terminate); 346 347 pidfile_write(pfh); 348 349 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 350 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 351 udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 352 tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 353 udpconf = getnetconfigent("udp"); 354 tcpconf = getnetconfigent("tcp"); 355 356 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 357 358 if (!have_v6) 359 goto skip_v6; 360 udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 361 tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 362 /* 363 * We're doing host-based access checks here, so don't allow 364 * v4-in-v6 to confuse things. The kernel will disable it 365 * by default on NFS sockets too. 366 */ 367 if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6, 368 IPV6_V6ONLY, &one, sizeof one) < 0) { 369 syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 370 exit(1); 371 } 372 if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6, 373 IPV6_V6ONLY, &one, sizeof one) < 0) { 374 syslog(LOG_ERR, "can't disable v4-in-v6 on TCP socket"); 375 exit(1); 376 } 377 udp6conf = getnetconfigent("udp6"); 378 tcp6conf = getnetconfigent("tcp6"); 379 380skip_v6: 381 if (!resvport_only) { 382 if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 383 &resvport_only, sizeof(resvport_only)) != 0 && 384 errno != ENOENT) { 385 syslog(LOG_ERR, "sysctl: %m"); 386 exit(1); 387 } 388 } 389 if (svcport != 0) { 390 bzero(&sin, sizeof(struct sockaddr_in)); 391 sin.sin_len = sizeof(struct sockaddr_in); 392 sin.sin_family = AF_INET; 393 sin.sin_port = htons(svcport); 394 395 bzero(&sin6, sizeof(struct sockaddr_in6)); 396 sin6.sin6_len = sizeof(struct sockaddr_in6); 397 sin6.sin6_family = AF_INET6; 398 sin6.sin6_port = htons(svcport); 399 } 400 if (udpsock != -1 && udpconf != NULL) { 401 if (svcport != 0) { 402 r = bindresvport(udpsock, &sin); 403 if (r != 0) { 404 syslog(LOG_ERR, "bindresvport: %m"); 405 exit(1); 406 } 407 } else 408 (void)bindresvport(udpsock, NULL); 409 udptransp = svc_dg_create(udpsock, 0, 0); 410 if (udptransp != NULL) { 411 if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, 412 mntsrv, udpconf)) 413 syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service"); 414 else 415 xcreated++; 416 if (!force_v2) { 417 if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3, 418 mntsrv, udpconf)) 419 syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service"); 420 else 421 xcreated++; 422 } 423 } else 424 syslog(LOG_WARNING, "can't create UDP services"); 425 426 } 427 if (tcpsock != -1 && tcpconf != NULL) { 428 if (svcport != 0) { 429 r = bindresvport(tcpsock, &sin); 430 if (r != 0) { 431 syslog(LOG_ERR, "bindresvport: %m"); 432 exit(1); 433 } 434 } else 435 (void)bindresvport(tcpsock, NULL); 436 listen(tcpsock, SOMAXCONN); 437 tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 438 if (tcptransp != NULL) { 439 if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1, 440 mntsrv, tcpconf)) 441 syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service"); 442 else 443 xcreated++; 444 if (!force_v2) { 445 if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3, 446 mntsrv, tcpconf)) 447 syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service"); 448 else 449 xcreated++; 450 } 451 } else 452 syslog(LOG_WARNING, "can't create TCP service"); 453 454 } 455 if (have_v6 && udp6sock != -1 && udp6conf != NULL) { 456 if (svcport != 0) { 457 r = bindresvport_sa(udp6sock, 458 (struct sockaddr *)&sin6); 459 if (r != 0) { 460 syslog(LOG_ERR, "bindresvport_sa: %m"); 461 exit(1); 462 } 463 } else 464 (void)bindresvport_sa(udp6sock, NULL); 465 udp6transp = svc_dg_create(udp6sock, 0, 0); 466 if (udp6transp != NULL) { 467 if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, 468 mntsrv, udp6conf)) 469 syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service"); 470 else 471 xcreated++; 472 if (!force_v2) { 473 if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3, 474 mntsrv, udp6conf)) 475 syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service"); 476 else 477 xcreated++; 478 } 479 } else 480 syslog(LOG_WARNING, "can't create UDP6 service"); 481 482 } 483 if (have_v6 && tcp6sock != -1 && tcp6conf != NULL) { 484 if (svcport != 0) { 485 r = bindresvport_sa(tcp6sock, 486 (struct sockaddr *)&sin6); 487 if (r != 0) { 488 syslog(LOG_ERR, "bindresvport_sa: %m"); 489 exit(1); 490 } 491 } else 492 (void)bindresvport_sa(tcp6sock, NULL); 493 listen(tcp6sock, SOMAXCONN); 494 tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 495 if (tcp6transp != NULL) { 496 if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1, 497 mntsrv, tcp6conf)) 498 syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service"); 499 else 500 xcreated++; 501 if (!force_v2) { 502 if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3, 503 mntsrv, tcp6conf)) 504 syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service"); 505 else 506 xcreated++; 507 } 508 } else 509 syslog(LOG_WARNING, "can't create TCP6 service"); 510 511 } 512 if (xcreated == 0) { 513 syslog(LOG_ERR, "could not create any services"); 514 exit(1); 515 } 516 517 /* Expand svc_run() here so that we can call get_exportlist(). */ 518 for (;;) { 519 if (got_sighup) { 520 get_exportlist(); 521 got_sighup = 0; 522 } 523 readfds = svc_fdset; 524 switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 525 case -1: 526 if (errno == EINTR) 527 continue; 528 syslog(LOG_ERR, "mountd died: select: %m"); 529 exit(1); 530 case 0: 531 continue; 532 default: 533 svc_getreqset(&readfds); 534 } 535 } 536} 537 538static void 539usage() 540{ 541 fprintf(stderr, 542 "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] " 543 "[export_file]\n"); 544 exit(1); 545} 546 547/* 548 * The mount rpc service 549 */ 550void 551mntsrv(rqstp, transp) 552 struct svc_req *rqstp; 553 SVCXPRT *transp; 554{ 555 struct exportlist *ep; 556 struct dirlist *dp; 557 struct fhreturn fhr; 558 struct stat stb; 559 struct statfs fsb; 560 char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 561 int lookup_failed = 1; 562 struct sockaddr *saddr; 563 u_short sport; 564 char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 565 int bad = 0, defset, hostset; 566 sigset_t sighup_mask; 567 568 sigemptyset(&sighup_mask); 569 sigaddset(&sighup_mask, SIGHUP); 570 saddr = svc_getrpccaller(transp)->buf; 571 switch (saddr->sa_family) { 572 case AF_INET6: 573 sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 574 break; 575 case AF_INET: 576 sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 577 break; 578 default: 579 syslog(LOG_ERR, "request from unknown address family"); 580 return; 581 } 582 lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 583 NULL, 0, 0); 584 getnameinfo(saddr, saddr->sa_len, numerichost, 585 sizeof numerichost, NULL, 0, NI_NUMERICHOST); 586 switch (rqstp->rq_proc) { 587 case NULLPROC: 588 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 589 syslog(LOG_ERR, "can't send reply"); 590 return; 591 case RPCMNT_MOUNT: 592 if (sport >= IPPORT_RESERVED && resvport_only) { 593 syslog(LOG_NOTICE, 594 "mount request from %s from unprivileged port", 595 numerichost); 596 svcerr_weakauth(transp); 597 return; 598 } 599 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 600 syslog(LOG_NOTICE, "undecodable mount request from %s", 601 numerichost); 602 svcerr_decode(transp); 603 return; 604 } 605 606 /* 607 * Get the real pathname and make sure it is a directory 608 * or a regular file if the -r option was specified 609 * and it exists. 610 */ 611 if (realpath(rpcpath, dirpath) == NULL || 612 stat(dirpath, &stb) < 0 || 613 (!S_ISDIR(stb.st_mode) && 614 (dir_only || !S_ISREG(stb.st_mode))) || 615 statfs(dirpath, &fsb) < 0) { 616 chdir("/"); /* Just in case realpath doesn't */ 617 syslog(LOG_NOTICE, 618 "mount request from %s for non existent path %s", 619 numerichost, dirpath); 620 if (debug) 621 warnx("stat failed on %s", dirpath); 622 bad = ENOENT; /* We will send error reply later */ 623 } 624 625 /* Check in the exports list */ 626 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 627 ep = ex_search(&fsb.f_fsid); 628 hostset = defset = 0; 629 if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 630 ((dp = dirp_search(ep->ex_dirl, dirpath)) && 631 chk_host(dp, saddr, &defset, &hostset)) || 632 (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 633 scan_tree(ep->ex_dirl, saddr) == 0))) { 634 if (bad) { 635 if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 636 (caddr_t)&bad)) 637 syslog(LOG_ERR, "can't send reply"); 638 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 639 return; 640 } 641 if (hostset & DP_HOSTSET) 642 fhr.fhr_flag = hostset; 643 else 644 fhr.fhr_flag = defset; 645 fhr.fhr_vers = rqstp->rq_vers; 646 /* Get the file handle */ 647 memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 648 if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 649 bad = errno; 650 syslog(LOG_ERR, "can't get fh for %s", dirpath); 651 if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 652 (caddr_t)&bad)) 653 syslog(LOG_ERR, "can't send reply"); 654 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 655 return; 656 } 657 if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 658 (caddr_t)&fhr)) 659 syslog(LOG_ERR, "can't send reply"); 660 if (!lookup_failed) 661 add_mlist(host, dirpath); 662 else 663 add_mlist(numerichost, dirpath); 664 if (debug) 665 warnx("mount successful"); 666 if (dolog) 667 syslog(LOG_NOTICE, 668 "mount request succeeded from %s for %s", 669 numerichost, dirpath); 670 } else { 671 bad = EACCES; 672 syslog(LOG_NOTICE, 673 "mount request denied from %s for %s", 674 numerichost, dirpath); 675 } 676 677 if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 678 (caddr_t)&bad)) 679 syslog(LOG_ERR, "can't send reply"); 680 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 681 return; 682 case RPCMNT_DUMP: 683 if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 684 syslog(LOG_ERR, "can't send reply"); 685 else if (dolog) 686 syslog(LOG_NOTICE, 687 "dump request succeeded from %s", 688 numerichost); 689 return; 690 case RPCMNT_UMOUNT: 691 if (sport >= IPPORT_RESERVED && resvport_only) { 692 syslog(LOG_NOTICE, 693 "umount request from %s from unprivileged port", 694 numerichost); 695 svcerr_weakauth(transp); 696 return; 697 } 698 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 699 syslog(LOG_NOTICE, "undecodable umount request from %s", 700 numerichost); 701 svcerr_decode(transp); 702 return; 703 } 704 if (realpath(rpcpath, dirpath) == NULL) { 705 syslog(LOG_NOTICE, "umount request from %s " 706 "for non existent path %s", 707 numerichost, dirpath); 708 } 709 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 710 syslog(LOG_ERR, "can't send reply"); 711 if (!lookup_failed) 712 del_mlist(host, dirpath); 713 del_mlist(numerichost, dirpath); 714 if (dolog) 715 syslog(LOG_NOTICE, 716 "umount request succeeded from %s for %s", 717 numerichost, dirpath); 718 return; 719 case RPCMNT_UMNTALL: 720 if (sport >= IPPORT_RESERVED && resvport_only) { 721 syslog(LOG_NOTICE, 722 "umountall request from %s from unprivileged port", 723 numerichost); 724 svcerr_weakauth(transp); 725 return; 726 } 727 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 728 syslog(LOG_ERR, "can't send reply"); 729 if (!lookup_failed) 730 del_mlist(host, NULL); 731 del_mlist(numerichost, NULL); 732 if (dolog) 733 syslog(LOG_NOTICE, 734 "umountall request succeeded from %s", 735 numerichost); 736 return; 737 case RPCMNT_EXPORT: 738 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 739 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 740 (caddr_t)NULL)) 741 syslog(LOG_ERR, "can't send reply"); 742 if (dolog) 743 syslog(LOG_NOTICE, 744 "export request succeeded from %s", 745 numerichost); 746 return; 747 default: 748 svcerr_noproc(transp); 749 return; 750 } 751} 752 753/* 754 * Xdr conversion for a dirpath string 755 */ 756int 757xdr_dir(xdrsp, dirp) 758 XDR *xdrsp; 759 char *dirp; 760{ 761 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 762} 763 764/* 765 * Xdr routine to generate file handle reply 766 */ 767int 768xdr_fhs(xdrsp, cp) 769 XDR *xdrsp; 770 caddr_t cp; 771{ 772 struct fhreturn *fhrp = (struct fhreturn *)cp; 773 u_long ok = 0, len, auth; 774 775 if (!xdr_long(xdrsp, &ok)) 776 return (0); 777 switch (fhrp->fhr_vers) { 778 case 1: 779 return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 780 case 3: 781 len = NFSX_V3FH; 782 if (!xdr_long(xdrsp, &len)) 783 return (0); 784 if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 785 return (0); 786 auth = RPCAUTH_UNIX; 787 len = 1; 788 if (!xdr_long(xdrsp, &len)) 789 return (0); 790 return (xdr_long(xdrsp, &auth)); 791 }; 792 return (0); 793} 794 795int 796xdr_mlist(xdrsp, cp) 797 XDR *xdrsp; 798 caddr_t cp; 799{ 800 struct mountlist *mlp; 801 int true = 1; 802 int false = 0; 803 char *strp; 804 805 mlp = mlhead; 806 while (mlp) { 807 if (!xdr_bool(xdrsp, &true)) 808 return (0); 809 strp = &mlp->ml_host[0]; 810 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 811 return (0); 812 strp = &mlp->ml_dirp[0]; 813 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 814 return (0); 815 mlp = mlp->ml_next; 816 } 817 if (!xdr_bool(xdrsp, &false)) 818 return (0); 819 return (1); 820} 821 822/* 823 * Xdr conversion for export list 824 */ 825int 826xdr_explist_common(xdrsp, cp, brief) 827 XDR *xdrsp; 828 caddr_t cp; 829 int brief; 830{ 831 struct exportlist *ep; 832 int false = 0; 833 int putdef; 834 sigset_t sighup_mask; 835 836 sigemptyset(&sighup_mask); 837 sigaddset(&sighup_mask, SIGHUP); 838 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 839 ep = exphead; 840 while (ep) { 841 putdef = 0; 842 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 843 &putdef, brief)) 844 goto errout; 845 if (ep->ex_defdir && putdef == 0 && 846 put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 847 &putdef, brief)) 848 goto errout; 849 ep = ep->ex_next; 850 } 851 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 852 if (!xdr_bool(xdrsp, &false)) 853 return (0); 854 return (1); 855errout: 856 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 857 return (0); 858} 859 860/* 861 * Called from xdr_explist() to traverse the tree and export the 862 * directory paths. 863 */ 864int 865put_exlist(dp, xdrsp, adp, putdefp, brief) 866 struct dirlist *dp; 867 XDR *xdrsp; 868 struct dirlist *adp; 869 int *putdefp; 870 int brief; 871{ 872 struct grouplist *grp; 873 struct hostlist *hp; 874 int true = 1; 875 int false = 0; 876 int gotalldir = 0; 877 char *strp; 878 879 if (dp) { 880 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 881 return (1); 882 if (!xdr_bool(xdrsp, &true)) 883 return (1); 884 strp = dp->dp_dirp; 885 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 886 return (1); 887 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 888 gotalldir = 1; 889 *putdefp = 1; 890 } 891 if (brief) { 892 if (!xdr_bool(xdrsp, &true)) 893 return (1); 894 strp = "(...)"; 895 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 896 return (1); 897 } else if ((dp->dp_flag & DP_DEFSET) == 0 && 898 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 899 hp = dp->dp_hosts; 900 while (hp) { 901 grp = hp->ht_grp; 902 if (grp->gr_type == GT_HOST) { 903 if (!xdr_bool(xdrsp, &true)) 904 return (1); 905 strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 906 if (!xdr_string(xdrsp, &strp, 907 RPCMNT_NAMELEN)) 908 return (1); 909 } else if (grp->gr_type == GT_NET) { 910 if (!xdr_bool(xdrsp, &true)) 911 return (1); 912 strp = grp->gr_ptr.gt_net.nt_name; 913 if (!xdr_string(xdrsp, &strp, 914 RPCMNT_NAMELEN)) 915 return (1); 916 } 917 hp = hp->ht_next; 918 if (gotalldir && hp == (struct hostlist *)NULL) { 919 hp = adp->dp_hosts; 920 gotalldir = 0; 921 } 922 } 923 } 924 if (!xdr_bool(xdrsp, &false)) 925 return (1); 926 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 927 return (1); 928 } 929 return (0); 930} 931 932int 933xdr_explist(xdrsp, cp) 934 XDR *xdrsp; 935 caddr_t cp; 936{ 937 938 return xdr_explist_common(xdrsp, cp, 0); 939} 940 941int 942xdr_explist_brief(xdrsp, cp) 943 XDR *xdrsp; 944 caddr_t cp; 945{ 946 947 return xdr_explist_common(xdrsp, cp, 1); 948} 949 950char *line; 951int linesize; 952FILE *exp_file; 953 954/* 955 * Get the export list 956 */ 957void 958get_exportlist() 959{ 960 struct exportlist *ep, *ep2; 961 struct grouplist *grp, *tgrp; 962 struct exportlist **epp;
|
| 963 struct export_args export;
|
966 struct dirlist *dirhead;
| 964 struct dirlist *dirhead;
|
| 965 struct iovec *iov;
|
967 struct statfs fsb, *fsp; 968 struct xucred anon; 969 char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
| 966 struct statfs fsb, *fsp; 967 struct xucred anon; 968 char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
|
| 969 char errmsg[255];
|
970 int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
| 970 int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
|
| 971 int iovlen;
|
971
| 972
|
| 973 bzero(&export, sizeof(export)); 974 export.ex_flags = MNT_DELEXPORT;
|
972 dirp = NULL; 973 dirplen = 0;
| 975 dirp = NULL; 976 dirplen = 0;
|
| 977 iov = NULL; 978 iovlen = 0; 979 bzero(errmsg, sizeof(errmsg));
|
974 975 /* 976 * First, get rid of the old list 977 */ 978 ep = exphead; 979 while (ep) { 980 ep2 = ep; 981 ep = ep->ex_next; 982 free_exp(ep2); 983 } 984 exphead = (struct exportlist *)NULL; 985 986 grp = grphead; 987 while (grp) { 988 tgrp = grp; 989 grp = grp->gr_next; 990 free_grp(tgrp); 991 } 992 grphead = (struct grouplist *)NULL; 993 994 /* 995 * And delete exports that are in the kernel for all local 996 * filesystems. 997 * XXX: Should know how to handle all local exportable filesystems 998 * instead of just "ufs". 999 */ 1000 num = getmntinfo(&fsp, MNT_NOWAIT);
| 980 981 /* 982 * First, get rid of the old list 983 */ 984 ep = exphead; 985 while (ep) { 986 ep2 = ep; 987 ep = ep->ex_next; 988 free_exp(ep2); 989 } 990 exphead = (struct exportlist *)NULL; 991 992 grp = grphead; 993 while (grp) { 994 tgrp = grp; 995 grp = grp->gr_next; 996 free_grp(tgrp); 997 } 998 grphead = (struct grouplist *)NULL; 999 1000 /* 1001 * And delete exports that are in the kernel for all local 1002 * filesystems. 1003 * XXX: Should know how to handle all local exportable filesystems 1004 * instead of just "ufs". 1005 */ 1006 num = getmntinfo(&fsp, MNT_NOWAIT);
|
| 1007 1008 if (num > 0) { 1009 build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1010 build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1011 build_iovec(&iov, &iovlen, "from", NULL, 0); 1012 build_iovec(&iov, &iovlen, "update", NULL, 0); 1013 build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1014 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1015 } 1016
|
1001 for (i = 0; i < num; i++) {
| 1017 for (i = 0; i < num; i++) {
|
1002 union { 1003 struct ufs_args ua; 1004 struct iso_args ia; 1005 struct msdosfs_args da; 1006 struct ntfs_args na; 1007 } targs;
| |
1008 1009 if (!strcmp(fsp->f_fstypename, "ufs") || 1010 !strcmp(fsp->f_fstypename, "msdosfs") || 1011 !strcmp(fsp->f_fstypename, "ntfs") || 1012 !strcmp(fsp->f_fstypename, "cd9660")) {
| 1018 1019 if (!strcmp(fsp->f_fstypename, "ufs") || 1020 !strcmp(fsp->f_fstypename, "msdosfs") || 1021 !strcmp(fsp->f_fstypename, "ntfs") || 1022 !strcmp(fsp->f_fstypename, "cd9660")) {
|
1013 bzero(&targs, sizeof targs); 1014 targs.ua.fspec = NULL; 1015 targs.ua.export.ex_flags = MNT_DELEXPORT; 1016 if (mount(fsp->f_fstypename, fsp->f_mntonname, 1017 fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0 && 1018 errno != ENOENT)
| 1023 iov[1].iov_base = fsp->f_fstypename; 1024 iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1025 iov[3].iov_base = fsp->f_mntonname; 1026 iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1027 iov[5].iov_base = fsp->f_mntfromname; 1028 iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1029 1030 /* 1031 * Kick out MNT_ROOTFS. It should not be passed from 1032 * userland to kernel. It should only be used 1033 * internally in the kernel. 1034 */ 1035 if (fsp->f_flags & MNT_ROOTFS) { 1036 fsp->f_flags &= ~MNT_ROOTFS; 1037 } 1038 1039 if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1040 errno != ENOENT) {
|
1019 syslog(LOG_ERR,
| 1041 syslog(LOG_ERR,
|
1020 "can't delete exports for %s: %m", 1021 fsp->f_mntonname);
| 1042 "can't delete exports for %s: %m %s", 1043 fsp->f_mntonname, errmsg); 1044 }
|
1022 } 1023 fsp++; 1024 } 1025
| 1045 } 1046 fsp++; 1047 } 1048
|
| 1049 if (iov != NULL) { 1050 /* Free strings allocated by strdup() in getmntopts.c */ 1051 free(iov[0].iov_base); /* fstype */ 1052 free(iov[2].iov_base); /* fspath */ 1053 free(iov[4].iov_base); /* from */ 1054 free(iov[6].iov_base); /* update */ 1055 free(iov[8].iov_base); /* export */ 1056 free(iov[10].iov_base); /* errmsg */ 1057 1058 /* free iov, allocated by realloc() */ 1059 free(iov); 1060 iovlen = 0; 1061 } 1062
|
1026 /* 1027 * Read in the exports file and build the list, calling
| 1063 /* 1064 * Read in the exports file and build the list, calling
|
1028 * mount() as we go along to push the export rules into the kernel.
| 1065 * nmount() as we go along to push the export rules into the kernel.
|
1029 */ 1030 if ((exp_file = fopen(exname, "r")) == NULL) { 1031 syslog(LOG_ERR, "can't open %s", exname); 1032 exit(2); 1033 } 1034 dirhead = (struct dirlist *)NULL; 1035 while (get_line()) { 1036 if (debug) 1037 warnx("got line %s", line); 1038 cp = line; 1039 nextfield(&cp, &endcp); 1040 if (*cp == '#') 1041 goto nextline; 1042 1043 /* 1044 * Set defaults. 1045 */ 1046 has_host = FALSE; 1047 anon = def_anon; 1048 exflags = MNT_EXPORTED; 1049 got_nondir = 0; 1050 opt_flags = 0; 1051 ep = (struct exportlist *)NULL; 1052 1053 /* 1054 * Create new exports list entry 1055 */ 1056 len = endcp-cp; 1057 tgrp = grp = get_grp(); 1058 while (len > 0) { 1059 if (len > RPCMNT_NAMELEN) { 1060 getexp_err(ep, tgrp); 1061 goto nextline; 1062 } 1063 if (*cp == '-') { 1064 if (ep == (struct exportlist *)NULL) { 1065 getexp_err(ep, tgrp); 1066 goto nextline; 1067 } 1068 if (debug) 1069 warnx("doing opt %s", cp); 1070 got_nondir = 1; 1071 if (do_opt(&cp, &endcp, ep, grp, &has_host, 1072 &exflags, &anon)) { 1073 getexp_err(ep, tgrp); 1074 goto nextline; 1075 } 1076 } else if (*cp == '/') { 1077 savedc = *endcp; 1078 *endcp = '\0'; 1079 if (check_dirpath(cp) && 1080 statfs(cp, &fsb) >= 0) { 1081 if (got_nondir) { 1082 syslog(LOG_ERR, "dirs must be first"); 1083 getexp_err(ep, tgrp); 1084 goto nextline; 1085 } 1086 if (ep) { 1087 if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 1088 ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 1089 getexp_err(ep, tgrp); 1090 goto nextline; 1091 } 1092 } else { 1093 /* 1094 * See if this directory is already 1095 * in the list. 1096 */ 1097 ep = ex_search(&fsb.f_fsid); 1098 if (ep == (struct exportlist *)NULL) { 1099 ep = get_exp(); 1100 ep->ex_fs = fsb.f_fsid; 1101 ep->ex_fsdir = (char *) 1102 malloc(strlen(fsb.f_mntonname) + 1); 1103 if (ep->ex_fsdir) 1104 strcpy(ep->ex_fsdir, 1105 fsb.f_mntonname); 1106 else 1107 out_of_mem(); 1108 if (debug) 1109 warnx("making new ep fs=0x%x,0x%x", 1110 fsb.f_fsid.val[0], 1111 fsb.f_fsid.val[1]); 1112 } else if (debug) 1113 warnx("found ep fs=0x%x,0x%x", 1114 fsb.f_fsid.val[0], 1115 fsb.f_fsid.val[1]); 1116 } 1117 1118 /* 1119 * Add dirpath to export mount point. 1120 */ 1121 dirp = add_expdir(&dirhead, cp, len); 1122 dirplen = len; 1123 } else { 1124 getexp_err(ep, tgrp); 1125 goto nextline; 1126 } 1127 *endcp = savedc; 1128 } else { 1129 savedc = *endcp; 1130 *endcp = '\0'; 1131 got_nondir = 1; 1132 if (ep == (struct exportlist *)NULL) { 1133 getexp_err(ep, tgrp); 1134 goto nextline; 1135 } 1136 1137 /* 1138 * Get the host or netgroup. 1139 */ 1140 setnetgrent(cp); 1141 netgrp = getnetgrent(&hst, &usr, &dom); 1142 do { 1143 if (has_host) { 1144 grp->gr_next = get_grp(); 1145 grp = grp->gr_next; 1146 } 1147 if (netgrp) { 1148 if (hst == 0) { 1149 syslog(LOG_ERR, 1150 "null hostname in netgroup %s, skipping", cp); 1151 grp->gr_type = GT_IGNORE; 1152 } else if (get_host(hst, grp, tgrp)) { 1153 syslog(LOG_ERR, 1154 "bad host %s in netgroup %s, skipping", hst, cp); 1155 grp->gr_type = GT_IGNORE; 1156 } 1157 } else if (get_host(cp, grp, tgrp)) { 1158 syslog(LOG_ERR, "bad host %s, skipping", cp); 1159 grp->gr_type = GT_IGNORE; 1160 } 1161 has_host = TRUE; 1162 } while (netgrp && getnetgrent(&hst, &usr, &dom)); 1163 endnetgrent(); 1164 *endcp = savedc; 1165 } 1166 cp = endcp; 1167 nextfield(&cp, &endcp); 1168 len = endcp - cp; 1169 } 1170 if (check_options(dirhead)) { 1171 getexp_err(ep, tgrp); 1172 goto nextline; 1173 } 1174 if (!has_host) { 1175 grp->gr_type = GT_DEFAULT; 1176 if (debug) 1177 warnx("adding a default entry"); 1178 1179 /* 1180 * Don't allow a network export coincide with a list of 1181 * host(s) on the same line. 1182 */ 1183 } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 1184 syslog(LOG_ERR, "network/host conflict"); 1185 getexp_err(ep, tgrp); 1186 goto nextline; 1187 1188 /* 1189 * If an export list was specified on this line, make sure 1190 * that we have at least one valid entry, otherwise skip it. 1191 */ 1192 } else { 1193 grp = tgrp; 1194 while (grp && grp->gr_type == GT_IGNORE) 1195 grp = grp->gr_next; 1196 if (! grp) { 1197 getexp_err(ep, tgrp); 1198 goto nextline; 1199 } 1200 } 1201 1202 /* 1203 * Loop through hosts, pushing the exports into the kernel. 1204 * After loop, tgrp points to the start of the list and 1205 * grp points to the last entry in the list. 1206 */ 1207 grp = tgrp; 1208 do { 1209 if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 1210 &fsb)) { 1211 getexp_err(ep, tgrp); 1212 goto nextline; 1213 } 1214 } while (grp->gr_next && (grp = grp->gr_next)); 1215 1216 /* 1217 * Success. Update the data structures. 1218 */ 1219 if (has_host) { 1220 hang_dirp(dirhead, tgrp, ep, opt_flags); 1221 grp->gr_next = grphead; 1222 grphead = tgrp; 1223 } else { 1224 hang_dirp(dirhead, (struct grouplist *)NULL, ep, 1225 opt_flags); 1226 free_grp(grp); 1227 } 1228 dirhead = (struct dirlist *)NULL; 1229 if ((ep->ex_flag & EX_LINKED) == 0) { 1230 ep2 = exphead; 1231 epp = &exphead; 1232 1233 /* 1234 * Insert in the list in alphabetical order. 1235 */ 1236 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 1237 epp = &ep2->ex_next; 1238 ep2 = ep2->ex_next; 1239 } 1240 if (ep2) 1241 ep->ex_next = ep2; 1242 *epp = ep; 1243 ep->ex_flag |= EX_LINKED; 1244 } 1245nextline: 1246 if (dirhead) { 1247 free_dir(dirhead); 1248 dirhead = (struct dirlist *)NULL; 1249 } 1250 } 1251 fclose(exp_file); 1252} 1253 1254/* 1255 * Allocate an export list element 1256 */ 1257struct exportlist * 1258get_exp() 1259{ 1260 struct exportlist *ep; 1261 1262 ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 1263 if (ep == (struct exportlist *)NULL) 1264 out_of_mem(); 1265 memset(ep, 0, sizeof(struct exportlist)); 1266 return (ep); 1267} 1268 1269/* 1270 * Allocate a group list element 1271 */ 1272struct grouplist * 1273get_grp() 1274{ 1275 struct grouplist *gp; 1276 1277 gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 1278 if (gp == (struct grouplist *)NULL) 1279 out_of_mem(); 1280 memset(gp, 0, sizeof(struct grouplist)); 1281 return (gp); 1282} 1283 1284/* 1285 * Clean up upon an error in get_exportlist(). 1286 */ 1287void 1288getexp_err(ep, grp) 1289 struct exportlist *ep; 1290 struct grouplist *grp; 1291{ 1292 struct grouplist *tgrp; 1293 1294 if (!(opt_flags & OP_QUIET)) 1295 syslog(LOG_ERR, "bad exports list line %s", line); 1296 if (ep && (ep->ex_flag & EX_LINKED) == 0) 1297 free_exp(ep); 1298 while (grp) { 1299 tgrp = grp; 1300 grp = grp->gr_next; 1301 free_grp(tgrp); 1302 } 1303} 1304 1305/* 1306 * Search the export list for a matching fs. 1307 */ 1308struct exportlist * 1309ex_search(fsid) 1310 fsid_t *fsid; 1311{ 1312 struct exportlist *ep; 1313 1314 ep = exphead; 1315 while (ep) { 1316 if (ep->ex_fs.val[0] == fsid->val[0] && 1317 ep->ex_fs.val[1] == fsid->val[1]) 1318 return (ep); 1319 ep = ep->ex_next; 1320 } 1321 return (ep); 1322} 1323 1324/* 1325 * Add a directory path to the list. 1326 */ 1327char * 1328add_expdir(dpp, cp, len) 1329 struct dirlist **dpp; 1330 char *cp; 1331 int len; 1332{ 1333 struct dirlist *dp; 1334 1335 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 1336 if (dp == (struct dirlist *)NULL) 1337 out_of_mem(); 1338 dp->dp_left = *dpp; 1339 dp->dp_right = (struct dirlist *)NULL; 1340 dp->dp_flag = 0; 1341 dp->dp_hosts = (struct hostlist *)NULL; 1342 strcpy(dp->dp_dirp, cp); 1343 *dpp = dp; 1344 return (dp->dp_dirp); 1345} 1346 1347/* 1348 * Hang the dir list element off the dirpath binary tree as required 1349 * and update the entry for host. 1350 */ 1351void 1352hang_dirp(dp, grp, ep, flags) 1353 struct dirlist *dp; 1354 struct grouplist *grp; 1355 struct exportlist *ep; 1356 int flags; 1357{ 1358 struct hostlist *hp; 1359 struct dirlist *dp2; 1360 1361 if (flags & OP_ALLDIRS) { 1362 if (ep->ex_defdir) 1363 free((caddr_t)dp); 1364 else 1365 ep->ex_defdir = dp; 1366 if (grp == (struct grouplist *)NULL) { 1367 ep->ex_defdir->dp_flag |= DP_DEFSET; 1368 } else while (grp) { 1369 hp = get_ht(); 1370 hp->ht_grp = grp; 1371 hp->ht_next = ep->ex_defdir->dp_hosts; 1372 ep->ex_defdir->dp_hosts = hp; 1373 grp = grp->gr_next; 1374 } 1375 } else { 1376 1377 /* 1378 * Loop through the directories adding them to the tree. 1379 */ 1380 while (dp) { 1381 dp2 = dp->dp_left; 1382 add_dlist(&ep->ex_dirl, dp, grp, flags); 1383 dp = dp2; 1384 } 1385 } 1386} 1387 1388/* 1389 * Traverse the binary tree either updating a node that is already there 1390 * for the new directory or adding the new node. 1391 */ 1392void 1393add_dlist(dpp, newdp, grp, flags) 1394 struct dirlist **dpp; 1395 struct dirlist *newdp; 1396 struct grouplist *grp; 1397 int flags; 1398{ 1399 struct dirlist *dp; 1400 struct hostlist *hp; 1401 int cmp; 1402 1403 dp = *dpp; 1404 if (dp) { 1405 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1406 if (cmp > 0) { 1407 add_dlist(&dp->dp_left, newdp, grp, flags); 1408 return; 1409 } else if (cmp < 0) { 1410 add_dlist(&dp->dp_right, newdp, grp, flags); 1411 return; 1412 } else 1413 free((caddr_t)newdp); 1414 } else { 1415 dp = newdp; 1416 dp->dp_left = (struct dirlist *)NULL; 1417 *dpp = dp; 1418 } 1419 if (grp) { 1420 1421 /* 1422 * Hang all of the host(s) off of the directory point. 1423 */ 1424 do { 1425 hp = get_ht(); 1426 hp->ht_grp = grp; 1427 hp->ht_next = dp->dp_hosts; 1428 dp->dp_hosts = hp; 1429 grp = grp->gr_next; 1430 } while (grp); 1431 } else { 1432 dp->dp_flag |= DP_DEFSET; 1433 } 1434} 1435 1436/* 1437 * Search for a dirpath on the export point. 1438 */ 1439struct dirlist * 1440dirp_search(dp, dirp) 1441 struct dirlist *dp; 1442 char *dirp; 1443{ 1444 int cmp; 1445 1446 if (dp) { 1447 cmp = strcmp(dp->dp_dirp, dirp); 1448 if (cmp > 0) 1449 return (dirp_search(dp->dp_left, dirp)); 1450 else if (cmp < 0) 1451 return (dirp_search(dp->dp_right, dirp)); 1452 else 1453 return (dp); 1454 } 1455 return (dp); 1456} 1457 1458/* 1459 * Scan for a host match in a directory tree. 1460 */ 1461int 1462chk_host(dp, saddr, defsetp, hostsetp) 1463 struct dirlist *dp; 1464 struct sockaddr *saddr; 1465 int *defsetp; 1466 int *hostsetp; 1467{ 1468 struct hostlist *hp; 1469 struct grouplist *grp; 1470 struct addrinfo *ai; 1471 1472 if (dp) { 1473 if (dp->dp_flag & DP_DEFSET) 1474 *defsetp = dp->dp_flag; 1475 hp = dp->dp_hosts; 1476 while (hp) { 1477 grp = hp->ht_grp; 1478 switch (grp->gr_type) { 1479 case GT_HOST: 1480 ai = grp->gr_ptr.gt_addrinfo; 1481 for (; ai; ai = ai->ai_next) { 1482 if (!sacmp(ai->ai_addr, saddr, NULL)) { 1483 *hostsetp = 1484 (hp->ht_flag | DP_HOSTSET); 1485 return (1); 1486 } 1487 } 1488 break; 1489 case GT_NET: 1490 if (!sacmp(saddr, (struct sockaddr *) 1491 &grp->gr_ptr.gt_net.nt_net, 1492 (struct sockaddr *) 1493 &grp->gr_ptr.gt_net.nt_mask)) { 1494 *hostsetp = (hp->ht_flag | DP_HOSTSET); 1495 return (1); 1496 } 1497 break; 1498 } 1499 hp = hp->ht_next; 1500 } 1501 } 1502 return (0); 1503} 1504 1505/* 1506 * Scan tree for a host that matches the address. 1507 */ 1508int 1509scan_tree(dp, saddr) 1510 struct dirlist *dp; 1511 struct sockaddr *saddr; 1512{ 1513 int defset, hostset; 1514 1515 if (dp) { 1516 if (scan_tree(dp->dp_left, saddr)) 1517 return (1); 1518 if (chk_host(dp, saddr, &defset, &hostset)) 1519 return (1); 1520 if (scan_tree(dp->dp_right, saddr)) 1521 return (1); 1522 } 1523 return (0); 1524} 1525 1526/* 1527 * Traverse the dirlist tree and free it up. 1528 */ 1529void 1530free_dir(dp) 1531 struct dirlist *dp; 1532{ 1533 1534 if (dp) { 1535 free_dir(dp->dp_left); 1536 free_dir(dp->dp_right); 1537 free_host(dp->dp_hosts); 1538 free((caddr_t)dp); 1539 } 1540} 1541 1542/* 1543 * Parse the option string and update fields. 1544 * Option arguments may either be -<option>=<value> or 1545 * -<option> <value> 1546 */ 1547int 1548do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1549 char **cpp, **endcpp; 1550 struct exportlist *ep; 1551 struct grouplist *grp; 1552 int *has_hostp; 1553 int *exflagsp; 1554 struct xucred *cr; 1555{ 1556 char *cpoptarg, *cpoptend; 1557 char *cp, *endcp, *cpopt, savedc, savedc2; 1558 int allflag, usedarg; 1559 1560 savedc2 = '\0'; 1561 cpopt = *cpp; 1562 cpopt++; 1563 cp = *endcpp; 1564 savedc = *cp; 1565 *cp = '\0'; 1566 while (cpopt && *cpopt) { 1567 allflag = 1; 1568 usedarg = -2; 1569 if ((cpoptend = strchr(cpopt, ','))) { 1570 *cpoptend++ = '\0'; 1571 if ((cpoptarg = strchr(cpopt, '='))) 1572 *cpoptarg++ = '\0'; 1573 } else { 1574 if ((cpoptarg = strchr(cpopt, '='))) 1575 *cpoptarg++ = '\0'; 1576 else { 1577 *cp = savedc; 1578 nextfield(&cp, &endcp); 1579 **endcpp = '\0'; 1580 if (endcp > cp && *cp != '-') { 1581 cpoptarg = cp; 1582 savedc2 = *endcp; 1583 *endcp = '\0'; 1584 usedarg = 0; 1585 } 1586 } 1587 } 1588 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1589 *exflagsp |= MNT_EXRDONLY; 1590 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1591 !(allflag = strcmp(cpopt, "mapall")) || 1592 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1593 usedarg++; 1594 parsecred(cpoptarg, cr); 1595 if (allflag == 0) { 1596 *exflagsp |= MNT_EXPORTANON; 1597 opt_flags |= OP_MAPALL; 1598 } else 1599 opt_flags |= OP_MAPROOT; 1600 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1601 !strcmp(cpopt, "m"))) { 1602 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1603 syslog(LOG_ERR, "bad mask: %s", cpoptarg); 1604 return (1); 1605 } 1606 usedarg++; 1607 opt_flags |= OP_MASK; 1608 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1609 !strcmp(cpopt, "n"))) { 1610 if (strchr(cpoptarg, '/') != NULL) { 1611 if (debug) 1612 fprintf(stderr, "setting OP_MASKLEN\n"); 1613 opt_flags |= OP_MASKLEN; 1614 } 1615 if (grp->gr_type != GT_NULL) { 1616 syslog(LOG_ERR, "network/host conflict"); 1617 return (1); 1618 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1619 syslog(LOG_ERR, "bad net: %s", cpoptarg); 1620 return (1); 1621 } 1622 grp->gr_type = GT_NET; 1623 *has_hostp = 1; 1624 usedarg++; 1625 opt_flags |= OP_NET; 1626 } else if (!strcmp(cpopt, "alldirs")) { 1627 opt_flags |= OP_ALLDIRS; 1628 } else if (!strcmp(cpopt, "public")) { 1629 *exflagsp |= MNT_EXPUBLIC; 1630 } else if (!strcmp(cpopt, "webnfs")) { 1631 *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 1632 opt_flags |= OP_MAPALL; 1633 } else if (cpoptarg && !strcmp(cpopt, "index")) { 1634 ep->ex_indexfile = strdup(cpoptarg); 1635 } else if (!strcmp(cpopt, "quiet")) { 1636 opt_flags |= OP_QUIET; 1637 } else { 1638 syslog(LOG_ERR, "bad opt %s", cpopt); 1639 return (1); 1640 } 1641 if (usedarg >= 0) { 1642 *endcp = savedc2; 1643 **endcpp = savedc; 1644 if (usedarg > 0) { 1645 *cpp = cp; 1646 *endcpp = endcp; 1647 } 1648 return (0); 1649 } 1650 cpopt = cpoptend; 1651 } 1652 **endcpp = savedc; 1653 return (0); 1654} 1655 1656/* 1657 * Translate a character string to the corresponding list of network 1658 * addresses for a hostname. 1659 */ 1660int 1661get_host(cp, grp, tgrp) 1662 char *cp; 1663 struct grouplist *grp; 1664 struct grouplist *tgrp; 1665{ 1666 struct grouplist *checkgrp; 1667 struct addrinfo *ai, *tai, hints; 1668 int ecode; 1669 char host[NI_MAXHOST]; 1670 1671 if (grp->gr_type != GT_NULL) { 1672 syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 1673 return (1); 1674 } 1675 memset(&hints, 0, sizeof hints); 1676 hints.ai_flags = AI_CANONNAME; 1677 hints.ai_protocol = IPPROTO_UDP; 1678 ecode = getaddrinfo(cp, NULL, &hints, &ai); 1679 if (ecode != 0) { 1680 syslog(LOG_ERR,"can't get address info for host %s", cp); 1681 return 1; 1682 } 1683 grp->gr_ptr.gt_addrinfo = ai; 1684 while (ai != NULL) { 1685 if (ai->ai_canonname == NULL) { 1686 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 1687 sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 1688 strlcpy(host, "?", sizeof(host)); 1689 ai->ai_canonname = strdup(host); 1690 ai->ai_flags |= AI_CANONNAME; 1691 } 1692 if (debug) 1693 fprintf(stderr, "got host %s\n", ai->ai_canonname); 1694 /* 1695 * Sanity check: make sure we don't already have an entry 1696 * for this host in the grouplist. 1697 */ 1698 for (checkgrp = tgrp; checkgrp != NULL; 1699 checkgrp = checkgrp->gr_next) { 1700 if (checkgrp->gr_type != GT_HOST) 1701 continue; 1702 for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 1703 tai = tai->ai_next) { 1704 if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 1705 continue; 1706 if (debug) 1707 fprintf(stderr, 1708 "ignoring duplicate host %s\n", 1709 ai->ai_canonname); 1710 grp->gr_type = GT_IGNORE; 1711 return (0); 1712 } 1713 } 1714 ai = ai->ai_next; 1715 } 1716 grp->gr_type = GT_HOST; 1717 return (0); 1718} 1719 1720/* 1721 * Free up an exports list component 1722 */ 1723void 1724free_exp(ep) 1725 struct exportlist *ep; 1726{ 1727 1728 if (ep->ex_defdir) { 1729 free_host(ep->ex_defdir->dp_hosts); 1730 free((caddr_t)ep->ex_defdir); 1731 } 1732 if (ep->ex_fsdir) 1733 free(ep->ex_fsdir); 1734 if (ep->ex_indexfile) 1735 free(ep->ex_indexfile); 1736 free_dir(ep->ex_dirl); 1737 free((caddr_t)ep); 1738} 1739 1740/* 1741 * Free hosts. 1742 */ 1743void 1744free_host(hp) 1745 struct hostlist *hp; 1746{ 1747 struct hostlist *hp2; 1748 1749 while (hp) { 1750 hp2 = hp; 1751 hp = hp->ht_next; 1752 free((caddr_t)hp2); 1753 } 1754} 1755 1756struct hostlist * 1757get_ht() 1758{ 1759 struct hostlist *hp; 1760 1761 hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 1762 if (hp == (struct hostlist *)NULL) 1763 out_of_mem(); 1764 hp->ht_next = (struct hostlist *)NULL; 1765 hp->ht_flag = 0; 1766 return (hp); 1767} 1768 1769/* 1770 * Out of memory, fatal 1771 */ 1772void 1773out_of_mem() 1774{ 1775 1776 syslog(LOG_ERR, "out of memory"); 1777 exit(2); 1778} 1779 1780/*
| 1066 */ 1067 if ((exp_file = fopen(exname, "r")) == NULL) { 1068 syslog(LOG_ERR, "can't open %s", exname); 1069 exit(2); 1070 } 1071 dirhead = (struct dirlist *)NULL; 1072 while (get_line()) { 1073 if (debug) 1074 warnx("got line %s", line); 1075 cp = line; 1076 nextfield(&cp, &endcp); 1077 if (*cp == '#') 1078 goto nextline; 1079 1080 /* 1081 * Set defaults. 1082 */ 1083 has_host = FALSE; 1084 anon = def_anon; 1085 exflags = MNT_EXPORTED; 1086 got_nondir = 0; 1087 opt_flags = 0; 1088 ep = (struct exportlist *)NULL; 1089 1090 /* 1091 * Create new exports list entry 1092 */ 1093 len = endcp-cp; 1094 tgrp = grp = get_grp(); 1095 while (len > 0) { 1096 if (len > RPCMNT_NAMELEN) { 1097 getexp_err(ep, tgrp); 1098 goto nextline; 1099 } 1100 if (*cp == '-') { 1101 if (ep == (struct exportlist *)NULL) { 1102 getexp_err(ep, tgrp); 1103 goto nextline; 1104 } 1105 if (debug) 1106 warnx("doing opt %s", cp); 1107 got_nondir = 1; 1108 if (do_opt(&cp, &endcp, ep, grp, &has_host, 1109 &exflags, &anon)) { 1110 getexp_err(ep, tgrp); 1111 goto nextline; 1112 } 1113 } else if (*cp == '/') { 1114 savedc = *endcp; 1115 *endcp = '\0'; 1116 if (check_dirpath(cp) && 1117 statfs(cp, &fsb) >= 0) { 1118 if (got_nondir) { 1119 syslog(LOG_ERR, "dirs must be first"); 1120 getexp_err(ep, tgrp); 1121 goto nextline; 1122 } 1123 if (ep) { 1124 if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 1125 ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 1126 getexp_err(ep, tgrp); 1127 goto nextline; 1128 } 1129 } else { 1130 /* 1131 * See if this directory is already 1132 * in the list. 1133 */ 1134 ep = ex_search(&fsb.f_fsid); 1135 if (ep == (struct exportlist *)NULL) { 1136 ep = get_exp(); 1137 ep->ex_fs = fsb.f_fsid; 1138 ep->ex_fsdir = (char *) 1139 malloc(strlen(fsb.f_mntonname) + 1); 1140 if (ep->ex_fsdir) 1141 strcpy(ep->ex_fsdir, 1142 fsb.f_mntonname); 1143 else 1144 out_of_mem(); 1145 if (debug) 1146 warnx("making new ep fs=0x%x,0x%x", 1147 fsb.f_fsid.val[0], 1148 fsb.f_fsid.val[1]); 1149 } else if (debug) 1150 warnx("found ep fs=0x%x,0x%x", 1151 fsb.f_fsid.val[0], 1152 fsb.f_fsid.val[1]); 1153 } 1154 1155 /* 1156 * Add dirpath to export mount point. 1157 */ 1158 dirp = add_expdir(&dirhead, cp, len); 1159 dirplen = len; 1160 } else { 1161 getexp_err(ep, tgrp); 1162 goto nextline; 1163 } 1164 *endcp = savedc; 1165 } else { 1166 savedc = *endcp; 1167 *endcp = '\0'; 1168 got_nondir = 1; 1169 if (ep == (struct exportlist *)NULL) { 1170 getexp_err(ep, tgrp); 1171 goto nextline; 1172 } 1173 1174 /* 1175 * Get the host or netgroup. 1176 */ 1177 setnetgrent(cp); 1178 netgrp = getnetgrent(&hst, &usr, &dom); 1179 do { 1180 if (has_host) { 1181 grp->gr_next = get_grp(); 1182 grp = grp->gr_next; 1183 } 1184 if (netgrp) { 1185 if (hst == 0) { 1186 syslog(LOG_ERR, 1187 "null hostname in netgroup %s, skipping", cp); 1188 grp->gr_type = GT_IGNORE; 1189 } else if (get_host(hst, grp, tgrp)) { 1190 syslog(LOG_ERR, 1191 "bad host %s in netgroup %s, skipping", hst, cp); 1192 grp->gr_type = GT_IGNORE; 1193 } 1194 } else if (get_host(cp, grp, tgrp)) { 1195 syslog(LOG_ERR, "bad host %s, skipping", cp); 1196 grp->gr_type = GT_IGNORE; 1197 } 1198 has_host = TRUE; 1199 } while (netgrp && getnetgrent(&hst, &usr, &dom)); 1200 endnetgrent(); 1201 *endcp = savedc; 1202 } 1203 cp = endcp; 1204 nextfield(&cp, &endcp); 1205 len = endcp - cp; 1206 } 1207 if (check_options(dirhead)) { 1208 getexp_err(ep, tgrp); 1209 goto nextline; 1210 } 1211 if (!has_host) { 1212 grp->gr_type = GT_DEFAULT; 1213 if (debug) 1214 warnx("adding a default entry"); 1215 1216 /* 1217 * Don't allow a network export coincide with a list of 1218 * host(s) on the same line. 1219 */ 1220 } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 1221 syslog(LOG_ERR, "network/host conflict"); 1222 getexp_err(ep, tgrp); 1223 goto nextline; 1224 1225 /* 1226 * If an export list was specified on this line, make sure 1227 * that we have at least one valid entry, otherwise skip it. 1228 */ 1229 } else { 1230 grp = tgrp; 1231 while (grp && grp->gr_type == GT_IGNORE) 1232 grp = grp->gr_next; 1233 if (! grp) { 1234 getexp_err(ep, tgrp); 1235 goto nextline; 1236 } 1237 } 1238 1239 /* 1240 * Loop through hosts, pushing the exports into the kernel. 1241 * After loop, tgrp points to the start of the list and 1242 * grp points to the last entry in the list. 1243 */ 1244 grp = tgrp; 1245 do { 1246 if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 1247 &fsb)) { 1248 getexp_err(ep, tgrp); 1249 goto nextline; 1250 } 1251 } while (grp->gr_next && (grp = grp->gr_next)); 1252 1253 /* 1254 * Success. Update the data structures. 1255 */ 1256 if (has_host) { 1257 hang_dirp(dirhead, tgrp, ep, opt_flags); 1258 grp->gr_next = grphead; 1259 grphead = tgrp; 1260 } else { 1261 hang_dirp(dirhead, (struct grouplist *)NULL, ep, 1262 opt_flags); 1263 free_grp(grp); 1264 } 1265 dirhead = (struct dirlist *)NULL; 1266 if ((ep->ex_flag & EX_LINKED) == 0) { 1267 ep2 = exphead; 1268 epp = &exphead; 1269 1270 /* 1271 * Insert in the list in alphabetical order. 1272 */ 1273 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 1274 epp = &ep2->ex_next; 1275 ep2 = ep2->ex_next; 1276 } 1277 if (ep2) 1278 ep->ex_next = ep2; 1279 *epp = ep; 1280 ep->ex_flag |= EX_LINKED; 1281 } 1282nextline: 1283 if (dirhead) { 1284 free_dir(dirhead); 1285 dirhead = (struct dirlist *)NULL; 1286 } 1287 } 1288 fclose(exp_file); 1289} 1290 1291/* 1292 * Allocate an export list element 1293 */ 1294struct exportlist * 1295get_exp() 1296{ 1297 struct exportlist *ep; 1298 1299 ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 1300 if (ep == (struct exportlist *)NULL) 1301 out_of_mem(); 1302 memset(ep, 0, sizeof(struct exportlist)); 1303 return (ep); 1304} 1305 1306/* 1307 * Allocate a group list element 1308 */ 1309struct grouplist * 1310get_grp() 1311{ 1312 struct grouplist *gp; 1313 1314 gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 1315 if (gp == (struct grouplist *)NULL) 1316 out_of_mem(); 1317 memset(gp, 0, sizeof(struct grouplist)); 1318 return (gp); 1319} 1320 1321/* 1322 * Clean up upon an error in get_exportlist(). 1323 */ 1324void 1325getexp_err(ep, grp) 1326 struct exportlist *ep; 1327 struct grouplist *grp; 1328{ 1329 struct grouplist *tgrp; 1330 1331 if (!(opt_flags & OP_QUIET)) 1332 syslog(LOG_ERR, "bad exports list line %s", line); 1333 if (ep && (ep->ex_flag & EX_LINKED) == 0) 1334 free_exp(ep); 1335 while (grp) { 1336 tgrp = grp; 1337 grp = grp->gr_next; 1338 free_grp(tgrp); 1339 } 1340} 1341 1342/* 1343 * Search the export list for a matching fs. 1344 */ 1345struct exportlist * 1346ex_search(fsid) 1347 fsid_t *fsid; 1348{ 1349 struct exportlist *ep; 1350 1351 ep = exphead; 1352 while (ep) { 1353 if (ep->ex_fs.val[0] == fsid->val[0] && 1354 ep->ex_fs.val[1] == fsid->val[1]) 1355 return (ep); 1356 ep = ep->ex_next; 1357 } 1358 return (ep); 1359} 1360 1361/* 1362 * Add a directory path to the list. 1363 */ 1364char * 1365add_expdir(dpp, cp, len) 1366 struct dirlist **dpp; 1367 char *cp; 1368 int len; 1369{ 1370 struct dirlist *dp; 1371 1372 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 1373 if (dp == (struct dirlist *)NULL) 1374 out_of_mem(); 1375 dp->dp_left = *dpp; 1376 dp->dp_right = (struct dirlist *)NULL; 1377 dp->dp_flag = 0; 1378 dp->dp_hosts = (struct hostlist *)NULL; 1379 strcpy(dp->dp_dirp, cp); 1380 *dpp = dp; 1381 return (dp->dp_dirp); 1382} 1383 1384/* 1385 * Hang the dir list element off the dirpath binary tree as required 1386 * and update the entry for host. 1387 */ 1388void 1389hang_dirp(dp, grp, ep, flags) 1390 struct dirlist *dp; 1391 struct grouplist *grp; 1392 struct exportlist *ep; 1393 int flags; 1394{ 1395 struct hostlist *hp; 1396 struct dirlist *dp2; 1397 1398 if (flags & OP_ALLDIRS) { 1399 if (ep->ex_defdir) 1400 free((caddr_t)dp); 1401 else 1402 ep->ex_defdir = dp; 1403 if (grp == (struct grouplist *)NULL) { 1404 ep->ex_defdir->dp_flag |= DP_DEFSET; 1405 } else while (grp) { 1406 hp = get_ht(); 1407 hp->ht_grp = grp; 1408 hp->ht_next = ep->ex_defdir->dp_hosts; 1409 ep->ex_defdir->dp_hosts = hp; 1410 grp = grp->gr_next; 1411 } 1412 } else { 1413 1414 /* 1415 * Loop through the directories adding them to the tree. 1416 */ 1417 while (dp) { 1418 dp2 = dp->dp_left; 1419 add_dlist(&ep->ex_dirl, dp, grp, flags); 1420 dp = dp2; 1421 } 1422 } 1423} 1424 1425/* 1426 * Traverse the binary tree either updating a node that is already there 1427 * for the new directory or adding the new node. 1428 */ 1429void 1430add_dlist(dpp, newdp, grp, flags) 1431 struct dirlist **dpp; 1432 struct dirlist *newdp; 1433 struct grouplist *grp; 1434 int flags; 1435{ 1436 struct dirlist *dp; 1437 struct hostlist *hp; 1438 int cmp; 1439 1440 dp = *dpp; 1441 if (dp) { 1442 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1443 if (cmp > 0) { 1444 add_dlist(&dp->dp_left, newdp, grp, flags); 1445 return; 1446 } else if (cmp < 0) { 1447 add_dlist(&dp->dp_right, newdp, grp, flags); 1448 return; 1449 } else 1450 free((caddr_t)newdp); 1451 } else { 1452 dp = newdp; 1453 dp->dp_left = (struct dirlist *)NULL; 1454 *dpp = dp; 1455 } 1456 if (grp) { 1457 1458 /* 1459 * Hang all of the host(s) off of the directory point. 1460 */ 1461 do { 1462 hp = get_ht(); 1463 hp->ht_grp = grp; 1464 hp->ht_next = dp->dp_hosts; 1465 dp->dp_hosts = hp; 1466 grp = grp->gr_next; 1467 } while (grp); 1468 } else { 1469 dp->dp_flag |= DP_DEFSET; 1470 } 1471} 1472 1473/* 1474 * Search for a dirpath on the export point. 1475 */ 1476struct dirlist * 1477dirp_search(dp, dirp) 1478 struct dirlist *dp; 1479 char *dirp; 1480{ 1481 int cmp; 1482 1483 if (dp) { 1484 cmp = strcmp(dp->dp_dirp, dirp); 1485 if (cmp > 0) 1486 return (dirp_search(dp->dp_left, dirp)); 1487 else if (cmp < 0) 1488 return (dirp_search(dp->dp_right, dirp)); 1489 else 1490 return (dp); 1491 } 1492 return (dp); 1493} 1494 1495/* 1496 * Scan for a host match in a directory tree. 1497 */ 1498int 1499chk_host(dp, saddr, defsetp, hostsetp) 1500 struct dirlist *dp; 1501 struct sockaddr *saddr; 1502 int *defsetp; 1503 int *hostsetp; 1504{ 1505 struct hostlist *hp; 1506 struct grouplist *grp; 1507 struct addrinfo *ai; 1508 1509 if (dp) { 1510 if (dp->dp_flag & DP_DEFSET) 1511 *defsetp = dp->dp_flag; 1512 hp = dp->dp_hosts; 1513 while (hp) { 1514 grp = hp->ht_grp; 1515 switch (grp->gr_type) { 1516 case GT_HOST: 1517 ai = grp->gr_ptr.gt_addrinfo; 1518 for (; ai; ai = ai->ai_next) { 1519 if (!sacmp(ai->ai_addr, saddr, NULL)) { 1520 *hostsetp = 1521 (hp->ht_flag | DP_HOSTSET); 1522 return (1); 1523 } 1524 } 1525 break; 1526 case GT_NET: 1527 if (!sacmp(saddr, (struct sockaddr *) 1528 &grp->gr_ptr.gt_net.nt_net, 1529 (struct sockaddr *) 1530 &grp->gr_ptr.gt_net.nt_mask)) { 1531 *hostsetp = (hp->ht_flag | DP_HOSTSET); 1532 return (1); 1533 } 1534 break; 1535 } 1536 hp = hp->ht_next; 1537 } 1538 } 1539 return (0); 1540} 1541 1542/* 1543 * Scan tree for a host that matches the address. 1544 */ 1545int 1546scan_tree(dp, saddr) 1547 struct dirlist *dp; 1548 struct sockaddr *saddr; 1549{ 1550 int defset, hostset; 1551 1552 if (dp) { 1553 if (scan_tree(dp->dp_left, saddr)) 1554 return (1); 1555 if (chk_host(dp, saddr, &defset, &hostset)) 1556 return (1); 1557 if (scan_tree(dp->dp_right, saddr)) 1558 return (1); 1559 } 1560 return (0); 1561} 1562 1563/* 1564 * Traverse the dirlist tree and free it up. 1565 */ 1566void 1567free_dir(dp) 1568 struct dirlist *dp; 1569{ 1570 1571 if (dp) { 1572 free_dir(dp->dp_left); 1573 free_dir(dp->dp_right); 1574 free_host(dp->dp_hosts); 1575 free((caddr_t)dp); 1576 } 1577} 1578 1579/* 1580 * Parse the option string and update fields. 1581 * Option arguments may either be -<option>=<value> or 1582 * -<option> <value> 1583 */ 1584int 1585do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1586 char **cpp, **endcpp; 1587 struct exportlist *ep; 1588 struct grouplist *grp; 1589 int *has_hostp; 1590 int *exflagsp; 1591 struct xucred *cr; 1592{ 1593 char *cpoptarg, *cpoptend; 1594 char *cp, *endcp, *cpopt, savedc, savedc2; 1595 int allflag, usedarg; 1596 1597 savedc2 = '\0'; 1598 cpopt = *cpp; 1599 cpopt++; 1600 cp = *endcpp; 1601 savedc = *cp; 1602 *cp = '\0'; 1603 while (cpopt && *cpopt) { 1604 allflag = 1; 1605 usedarg = -2; 1606 if ((cpoptend = strchr(cpopt, ','))) { 1607 *cpoptend++ = '\0'; 1608 if ((cpoptarg = strchr(cpopt, '='))) 1609 *cpoptarg++ = '\0'; 1610 } else { 1611 if ((cpoptarg = strchr(cpopt, '='))) 1612 *cpoptarg++ = '\0'; 1613 else { 1614 *cp = savedc; 1615 nextfield(&cp, &endcp); 1616 **endcpp = '\0'; 1617 if (endcp > cp && *cp != '-') { 1618 cpoptarg = cp; 1619 savedc2 = *endcp; 1620 *endcp = '\0'; 1621 usedarg = 0; 1622 } 1623 } 1624 } 1625 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1626 *exflagsp |= MNT_EXRDONLY; 1627 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1628 !(allflag = strcmp(cpopt, "mapall")) || 1629 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1630 usedarg++; 1631 parsecred(cpoptarg, cr); 1632 if (allflag == 0) { 1633 *exflagsp |= MNT_EXPORTANON; 1634 opt_flags |= OP_MAPALL; 1635 } else 1636 opt_flags |= OP_MAPROOT; 1637 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1638 !strcmp(cpopt, "m"))) { 1639 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1640 syslog(LOG_ERR, "bad mask: %s", cpoptarg); 1641 return (1); 1642 } 1643 usedarg++; 1644 opt_flags |= OP_MASK; 1645 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1646 !strcmp(cpopt, "n"))) { 1647 if (strchr(cpoptarg, '/') != NULL) { 1648 if (debug) 1649 fprintf(stderr, "setting OP_MASKLEN\n"); 1650 opt_flags |= OP_MASKLEN; 1651 } 1652 if (grp->gr_type != GT_NULL) { 1653 syslog(LOG_ERR, "network/host conflict"); 1654 return (1); 1655 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1656 syslog(LOG_ERR, "bad net: %s", cpoptarg); 1657 return (1); 1658 } 1659 grp->gr_type = GT_NET; 1660 *has_hostp = 1; 1661 usedarg++; 1662 opt_flags |= OP_NET; 1663 } else if (!strcmp(cpopt, "alldirs")) { 1664 opt_flags |= OP_ALLDIRS; 1665 } else if (!strcmp(cpopt, "public")) { 1666 *exflagsp |= MNT_EXPUBLIC; 1667 } else if (!strcmp(cpopt, "webnfs")) { 1668 *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 1669 opt_flags |= OP_MAPALL; 1670 } else if (cpoptarg && !strcmp(cpopt, "index")) { 1671 ep->ex_indexfile = strdup(cpoptarg); 1672 } else if (!strcmp(cpopt, "quiet")) { 1673 opt_flags |= OP_QUIET; 1674 } else { 1675 syslog(LOG_ERR, "bad opt %s", cpopt); 1676 return (1); 1677 } 1678 if (usedarg >= 0) { 1679 *endcp = savedc2; 1680 **endcpp = savedc; 1681 if (usedarg > 0) { 1682 *cpp = cp; 1683 *endcpp = endcp; 1684 } 1685 return (0); 1686 } 1687 cpopt = cpoptend; 1688 } 1689 **endcpp = savedc; 1690 return (0); 1691} 1692 1693/* 1694 * Translate a character string to the corresponding list of network 1695 * addresses for a hostname. 1696 */ 1697int 1698get_host(cp, grp, tgrp) 1699 char *cp; 1700 struct grouplist *grp; 1701 struct grouplist *tgrp; 1702{ 1703 struct grouplist *checkgrp; 1704 struct addrinfo *ai, *tai, hints; 1705 int ecode; 1706 char host[NI_MAXHOST]; 1707 1708 if (grp->gr_type != GT_NULL) { 1709 syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 1710 return (1); 1711 } 1712 memset(&hints, 0, sizeof hints); 1713 hints.ai_flags = AI_CANONNAME; 1714 hints.ai_protocol = IPPROTO_UDP; 1715 ecode = getaddrinfo(cp, NULL, &hints, &ai); 1716 if (ecode != 0) { 1717 syslog(LOG_ERR,"can't get address info for host %s", cp); 1718 return 1; 1719 } 1720 grp->gr_ptr.gt_addrinfo = ai; 1721 while (ai != NULL) { 1722 if (ai->ai_canonname == NULL) { 1723 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 1724 sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 1725 strlcpy(host, "?", sizeof(host)); 1726 ai->ai_canonname = strdup(host); 1727 ai->ai_flags |= AI_CANONNAME; 1728 } 1729 if (debug) 1730 fprintf(stderr, "got host %s\n", ai->ai_canonname); 1731 /* 1732 * Sanity check: make sure we don't already have an entry 1733 * for this host in the grouplist. 1734 */ 1735 for (checkgrp = tgrp; checkgrp != NULL; 1736 checkgrp = checkgrp->gr_next) { 1737 if (checkgrp->gr_type != GT_HOST) 1738 continue; 1739 for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 1740 tai = tai->ai_next) { 1741 if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 1742 continue; 1743 if (debug) 1744 fprintf(stderr, 1745 "ignoring duplicate host %s\n", 1746 ai->ai_canonname); 1747 grp->gr_type = GT_IGNORE; 1748 return (0); 1749 } 1750 } 1751 ai = ai->ai_next; 1752 } 1753 grp->gr_type = GT_HOST; 1754 return (0); 1755} 1756 1757/* 1758 * Free up an exports list component 1759 */ 1760void 1761free_exp(ep) 1762 struct exportlist *ep; 1763{ 1764 1765 if (ep->ex_defdir) { 1766 free_host(ep->ex_defdir->dp_hosts); 1767 free((caddr_t)ep->ex_defdir); 1768 } 1769 if (ep->ex_fsdir) 1770 free(ep->ex_fsdir); 1771 if (ep->ex_indexfile) 1772 free(ep->ex_indexfile); 1773 free_dir(ep->ex_dirl); 1774 free((caddr_t)ep); 1775} 1776 1777/* 1778 * Free hosts. 1779 */ 1780void 1781free_host(hp) 1782 struct hostlist *hp; 1783{ 1784 struct hostlist *hp2; 1785 1786 while (hp) { 1787 hp2 = hp; 1788 hp = hp->ht_next; 1789 free((caddr_t)hp2); 1790 } 1791} 1792 1793struct hostlist * 1794get_ht() 1795{ 1796 struct hostlist *hp; 1797 1798 hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 1799 if (hp == (struct hostlist *)NULL) 1800 out_of_mem(); 1801 hp->ht_next = (struct hostlist *)NULL; 1802 hp->ht_flag = 0; 1803 return (hp); 1804} 1805 1806/* 1807 * Out of memory, fatal 1808 */ 1809void 1810out_of_mem() 1811{ 1812 1813 syslog(LOG_ERR, "out of memory"); 1814 exit(2); 1815} 1816 1817/*
|
1781 * Do the mount syscall with the update flag to push the export info into
| 1818 * Do the nmount() syscall with the update flag to push the export info into
|
1782 * the kernel. 1783 */ 1784int
| 1819 * the kernel. 1820 */ 1821int
|
1785do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 1786 struct exportlist *ep; 1787 struct grouplist *grp; 1788 int exflags; 1789 struct xucred *anoncrp; 1790 char *dirp; 1791 int dirplen; 1792 struct statfs *fsb;
| 1822do_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 1823 struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb)
|
1793{ 1794 struct statfs fsb1; 1795 struct addrinfo *ai;
| 1824{ 1825 struct statfs fsb1; 1826 struct addrinfo *ai;
|
1796 struct export_args *eap; 1797 char *cp = NULL;
| 1827 struct export_args eap; 1828 char errmsg[255]; 1829 char *cp;
|
1798 int done;
| 1830 int done;
|
1799 char savedc = '\0'; 1800 union { 1801 struct ufs_args ua; 1802 struct iso_args ia; 1803 struct msdosfs_args da; 1804 struct ntfs_args na; 1805 } args;
| 1831 char savedc; 1832 struct iovec *iov; 1833 int iovlen; 1834 int ret;
|
1806
| 1835
|
1807 bzero(&args, sizeof args); 1808 /* XXX, we assume that all xx_args look like ufs_args. */ 1809 args.ua.fspec = 0; 1810 eap = &args.ua.export;
| 1836 cp = NULL; 1837 savedc = '\0'; 1838 iov = NULL; 1839 iovlen = 0; 1840 ret = 0;
|
1811
| 1841
|
1812 eap->ex_flags = exflags; 1813 eap->ex_anon = *anoncrp; 1814 eap->ex_indexfile = ep->ex_indexfile;
| 1842 bzero(&eap, sizeof(eap)); 1843 bzero(errmsg, sizeof(errmsg)); 1844 eap.ex_flags = exflags; 1845 eap.ex_anon = *anoncrp; 1846 eap.ex_indexfile = ep->ex_indexfile;
|
1815 if (grp->gr_type == GT_HOST) 1816 ai = grp->gr_ptr.gt_addrinfo; 1817 else 1818 ai = NULL; 1819 done = FALSE;
| 1847 if (grp->gr_type == GT_HOST) 1848 ai = grp->gr_ptr.gt_addrinfo; 1849 else 1850 ai = NULL; 1851 done = FALSE;
|
| 1852 1853 build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1854 build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1855 build_iovec(&iov, &iovlen, "from", NULL, 0); 1856 build_iovec(&iov, &iovlen, "update", NULL, 0); 1857 build_iovec(&iov, &iovlen, "export", &eap, sizeof(eap)); 1858 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1859
|
1820 while (!done) { 1821 switch (grp->gr_type) { 1822 case GT_HOST: 1823 if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 1824 goto skip;
| 1860 while (!done) { 1861 switch (grp->gr_type) { 1862 case GT_HOST: 1863 if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 1864 goto skip;
|
1825 eap->ex_addr = ai->ai_addr; 1826 eap->ex_addrlen = ai->ai_addrlen; 1827 eap->ex_masklen = 0;
| 1865 eap.ex_addr = ai->ai_addr; 1866 eap.ex_addrlen = ai->ai_addrlen; 1867 eap.ex_masklen = 0;
|
1828 break; 1829 case GT_NET: 1830 if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 1831 have_v6 == 0) 1832 goto skip;
| 1868 break; 1869 case GT_NET: 1870 if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 1871 have_v6 == 0) 1872 goto skip;
|
1833 eap->ex_addr =
| 1873 eap.ex_addr =
|
1834 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net;
| 1874 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net;
|
1835 eap->ex_addrlen = args.ua.export.ex_addr->sa_len; 1836 eap->ex_mask =
| 1875 eap.ex_addrlen = 1876 ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 1877 eap.ex_mask =
|
1837 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask;
| 1878 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask;
|
1838 eap->ex_masklen = args.ua.export.ex_mask->sa_len;
| 1879 eap.ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len;
|
1839 break; 1840 case GT_DEFAULT:
| 1880 break; 1881 case GT_DEFAULT:
|
1841 eap->ex_addr = NULL; 1842 eap->ex_addrlen = 0; 1843 eap->ex_mask = NULL; 1844 eap->ex_masklen = 0;
| 1882 eap.ex_addr = NULL; 1883 eap.ex_addrlen = 0; 1884 eap.ex_mask = NULL; 1885 eap.ex_masklen = 0;
|
1845 break; 1846 case GT_IGNORE:
| 1886 break; 1887 case GT_IGNORE:
|
1847 return(0);
| 1888 ret = 0; 1889 goto error_exit;
|
1848 break; 1849 default: 1850 syslog(LOG_ERR, "bad grouptype"); 1851 if (cp) 1852 *cp = savedc;
| 1890 break; 1891 default: 1892 syslog(LOG_ERR, "bad grouptype"); 1893 if (cp) 1894 *cp = savedc;
|
1853 return (1);
| 1895 ret = 1; 1896 goto error_exit;
|
1854 }; 1855 1856 /* 1857 * XXX: 1858 * Maybe I should just use the fsb->f_mntonname path instead 1859 * of looping back up the dirp to the mount point?? 1860 * Also, needs to know how to export all types of local 1861 * exportable filesystems and not just "ufs". 1862 */
| 1897 }; 1898 1899 /* 1900 * XXX: 1901 * Maybe I should just use the fsb->f_mntonname path instead 1902 * of looping back up the dirp to the mount point?? 1903 * Also, needs to know how to export all types of local 1904 * exportable filesystems and not just "ufs". 1905 */
|
1863 while (mount(fsb->f_fstypename, dirp, 1864 fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
| 1906 iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 1907 iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 1908 iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 1909 iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 1910 iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 1911 iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 1912 1913 while (nmount(iov, iovlen, 0) < 0) {
|
1865 if (cp) 1866 *cp-- = savedc; 1867 else 1868 cp = dirp + dirplen - 1;
| 1914 if (cp) 1915 *cp-- = savedc; 1916 else 1917 cp = dirp + dirplen - 1;
|
1869 if (opt_flags & OP_QUIET) 1870 return (1);
| 1918 if (opt_flags & OP_QUIET) { 1919 ret = 1; 1920 goto error_exit; 1921 }
|
1871 if (errno == EPERM) { 1872 if (debug) 1873 warnx("can't change attributes for %s", 1874 dirp); 1875 syslog(LOG_ERR, 1876 "can't change attributes for %s", dirp);
| 1922 if (errno == EPERM) { 1923 if (debug) 1924 warnx("can't change attributes for %s", 1925 dirp); 1926 syslog(LOG_ERR, 1927 "can't change attributes for %s", dirp);
|
1877 return (1);
| 1928 ret = 1; 1929 goto error_exit;
|
1878 } 1879 if (opt_flags & OP_ALLDIRS) { 1880 if (errno == EINVAL) 1881 syslog(LOG_ERR, 1882 "-alldirs requested but %s is not a filesystem mountpoint", 1883 dirp); 1884 else 1885 syslog(LOG_ERR, 1886 "could not remount %s: %m", 1887 dirp);
| 1930 } 1931 if (opt_flags & OP_ALLDIRS) { 1932 if (errno == EINVAL) 1933 syslog(LOG_ERR, 1934 "-alldirs requested but %s is not a filesystem mountpoint", 1935 dirp); 1936 else 1937 syslog(LOG_ERR, 1938 "could not remount %s: %m", 1939 dirp);
|
1888 return (1);
| 1940 ret = 1; 1941 goto error_exit;
|
1889 } 1890 /* back up over the last component */ 1891 while (*cp == '/' && cp > dirp) 1892 cp--; 1893 while (*(cp - 1) != '/' && cp > dirp) 1894 cp--; 1895 if (cp == dirp) { 1896 if (debug) 1897 warnx("mnt unsucc"); 1898 syslog(LOG_ERR, "can't export %s", dirp);
| 1942 } 1943 /* back up over the last component */ 1944 while (*cp == '/' && cp > dirp) 1945 cp--; 1946 while (*(cp - 1) != '/' && cp > dirp) 1947 cp--; 1948 if (cp == dirp) { 1949 if (debug) 1950 warnx("mnt unsucc"); 1951 syslog(LOG_ERR, "can't export %s", dirp);
|
1899 return (1);
| 1952 ret = 1; 1953 goto error_exit;
|
1900 } 1901 savedc = *cp; 1902 *cp = '\0'; 1903 /* Check that we're still on the same filesystem. */ 1904 if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid, 1905 &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) { 1906 *cp = savedc; 1907 syslog(LOG_ERR, "can't export %s", dirp);
| 1954 } 1955 savedc = *cp; 1956 *cp = '\0'; 1957 /* Check that we're still on the same filesystem. */ 1958 if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid, 1959 &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) { 1960 *cp = savedc; 1961 syslog(LOG_ERR, "can't export %s", dirp);
|
1908 return (1);
| 1962 ret = 1; 1963 goto error_exit;
|
1909 } 1910 } 1911skip: 1912 if (ai != NULL) 1913 ai = ai->ai_next; 1914 if (ai == NULL) 1915 done = TRUE; 1916 } 1917 if (cp) 1918 *cp = savedc;
| 1964 } 1965 } 1966skip: 1967 if (ai != NULL) 1968 ai = ai->ai_next; 1969 if (ai == NULL) 1970 done = TRUE; 1971 } 1972 if (cp) 1973 *cp = savedc;
|
1919 return (0);
| 1974error_exit: 1975 /* free strings allocated by strdup() in getmntopts.c */ 1976 if (iov != NULL) { 1977 free(iov[0].iov_base); /* fstype */ 1978 free(iov[2].iov_base); /* fspath */ 1979 free(iov[4].iov_base); /* from */ 1980 free(iov[6].iov_base); /* update */ 1981 free(iov[8].iov_base); /* export */ 1982 free(iov[10].iov_base); /* errmsg */ 1983 1984 /* free iov, allocated by realloc() */ 1985 free(iov); 1986 } 1987 return (ret);
|
1920} 1921 1922/* 1923 * Translate a net address. 1924 * 1925 * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 1926 */ 1927int 1928get_net(cp, net, maskflg) 1929 char *cp; 1930 struct netmsk *net; 1931 int maskflg; 1932{ 1933 struct netent *np = NULL; 1934 char *name, *p, *prefp; 1935 struct sockaddr_in sin; 1936 struct sockaddr *sa = NULL; 1937 struct addrinfo hints, *ai = NULL; 1938 char netname[NI_MAXHOST]; 1939 long preflen; 1940 1941 p = prefp = NULL; 1942 if ((opt_flags & OP_MASKLEN) && !maskflg) { 1943 p = strchr(cp, '/'); 1944 *p = '\0'; 1945 prefp = p + 1; 1946 } 1947 1948 /* 1949 * Check for a numeric address first. We wish to avoid 1950 * possible DNS lookups in getnetbyname(). 1951 */ 1952 if (isxdigit(*cp) || *cp == ':') { 1953 memset(&hints, 0, sizeof hints); 1954 /* Ensure the mask and the network have the same family. */ 1955 if (maskflg && (opt_flags & OP_NET)) 1956 hints.ai_family = net->nt_net.ss_family; 1957 else if (!maskflg && (opt_flags & OP_HAVEMASK)) 1958 hints.ai_family = net->nt_mask.ss_family; 1959 else 1960 hints.ai_family = AF_UNSPEC; 1961 hints.ai_flags = AI_NUMERICHOST; 1962 if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 1963 sa = ai->ai_addr; 1964 if (sa != NULL && ai->ai_family == AF_INET) { 1965 /* 1966 * The address in `cp' is really a network address, so 1967 * use inet_network() to re-interpret this correctly. 1968 * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 1969 */ 1970 bzero(&sin, sizeof sin); 1971 sin.sin_family = AF_INET; 1972 sin.sin_len = sizeof sin; 1973 sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 1974 if (debug) 1975 fprintf(stderr, "get_net: v4 addr %s\n", 1976 inet_ntoa(sin.sin_addr)); 1977 sa = (struct sockaddr *)&sin; 1978 } 1979 } 1980 if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 1981 bzero(&sin, sizeof sin); 1982 sin.sin_family = AF_INET; 1983 sin.sin_len = sizeof sin; 1984 sin.sin_addr = inet_makeaddr(np->n_net, 0); 1985 sa = (struct sockaddr *)&sin; 1986 } 1987 if (sa == NULL) 1988 goto fail; 1989 1990 if (maskflg) { 1991 /* The specified sockaddr is a mask. */ 1992 if (checkmask(sa) != 0) 1993 goto fail; 1994 bcopy(sa, &net->nt_mask, sa->sa_len); 1995 opt_flags |= OP_HAVEMASK; 1996 } else { 1997 /* The specified sockaddr is a network address. */ 1998 bcopy(sa, &net->nt_net, sa->sa_len); 1999 2000 /* Get a network name for the export list. */ 2001 if (np) { 2002 name = np->n_name; 2003 } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2004 NULL, 0, NI_NUMERICHOST) == 0) { 2005 name = netname; 2006 } else { 2007 goto fail; 2008 } 2009 if ((net->nt_name = strdup(name)) == NULL) 2010 out_of_mem(); 2011 2012 /* 2013 * Extract a mask from either a "/<masklen>" suffix, or 2014 * from the class of an IPv4 address. 2015 */ 2016 if (opt_flags & OP_MASKLEN) { 2017 preflen = strtol(prefp, NULL, 10); 2018 if (preflen < 0L || preflen == LONG_MAX) 2019 goto fail; 2020 bcopy(sa, &net->nt_mask, sa->sa_len); 2021 if (makemask(&net->nt_mask, (int)preflen) != 0) 2022 goto fail; 2023 opt_flags |= OP_HAVEMASK; 2024 *p = '/'; 2025 } else if (sa->sa_family == AF_INET && 2026 (opt_flags & OP_MASK) == 0) { 2027 in_addr_t addr; 2028 2029 addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 2030 if (IN_CLASSA(addr)) 2031 preflen = 8; 2032 else if (IN_CLASSB(addr)) 2033 preflen = 16; 2034 else if (IN_CLASSC(addr)) 2035 preflen = 24; 2036 else if (IN_CLASSD(addr)) 2037 preflen = 28; 2038 else 2039 preflen = 32; /* XXX */ 2040 2041 bcopy(sa, &net->nt_mask, sa->sa_len); 2042 makemask(&net->nt_mask, (int)preflen); 2043 opt_flags |= OP_HAVEMASK; 2044 } 2045 } 2046 2047 if (ai) 2048 freeaddrinfo(ai); 2049 return 0; 2050 2051fail: 2052 if (ai) 2053 freeaddrinfo(ai); 2054 return 1; 2055} 2056 2057/* 2058 * Parse out the next white space separated field 2059 */ 2060void 2061nextfield(cp, endcp) 2062 char **cp; 2063 char **endcp; 2064{ 2065 char *p; 2066 2067 p = *cp; 2068 while (*p == ' ' || *p == '\t') 2069 p++; 2070 if (*p == '\n' || *p == '\0') 2071 *cp = *endcp = p; 2072 else { 2073 *cp = p++; 2074 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 2075 p++; 2076 *endcp = p; 2077 } 2078} 2079 2080/* 2081 * Get an exports file line. Skip over blank lines and handle line 2082 * continuations. 2083 */ 2084int 2085get_line() 2086{ 2087 char *p, *cp; 2088 size_t len; 2089 int totlen, cont_line; 2090 2091 /* 2092 * Loop around ignoring blank lines and getting all continuation lines. 2093 */ 2094 p = line; 2095 totlen = 0; 2096 do { 2097 if ((p = fgetln(exp_file, &len)) == NULL) 2098 return (0); 2099 cp = p + len - 1; 2100 cont_line = 0; 2101 while (cp >= p && 2102 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 2103 if (*cp == '\\') 2104 cont_line = 1; 2105 cp--; 2106 len--; 2107 } 2108 if (cont_line) { 2109 *++cp = ' '; 2110 len++; 2111 } 2112 if (linesize < len + totlen + 1) { 2113 linesize = len + totlen + 1; 2114 line = realloc(line, linesize); 2115 if (line == NULL) 2116 out_of_mem(); 2117 } 2118 memcpy(line + totlen, p, len); 2119 totlen += len; 2120 line[totlen] = '\0'; 2121 } while (totlen == 0 || cont_line); 2122 return (1); 2123} 2124 2125/* 2126 * Parse a description of a credential. 2127 */ 2128void 2129parsecred(namelist, cr) 2130 char *namelist; 2131 struct xucred *cr; 2132{ 2133 char *name; 2134 int cnt; 2135 char *names; 2136 struct passwd *pw; 2137 struct group *gr; 2138 gid_t groups[NGROUPS + 1]; 2139 int ngroups; 2140 2141 cr->cr_version = XUCRED_VERSION; 2142 /* 2143 * Set up the unprivileged user. 2144 */ 2145 cr->cr_uid = -2; 2146 cr->cr_groups[0] = -2; 2147 cr->cr_ngroups = 1; 2148 /* 2149 * Get the user's password table entry. 2150 */ 2151 names = strsep(&namelist, " \t\n"); 2152 name = strsep(&names, ":"); 2153 if (isdigit(*name) || *name == '-') 2154 pw = getpwuid(atoi(name)); 2155 else 2156 pw = getpwnam(name); 2157 /* 2158 * Credentials specified as those of a user. 2159 */ 2160 if (names == NULL) { 2161 if (pw == NULL) { 2162 syslog(LOG_ERR, "unknown user: %s", name); 2163 return; 2164 } 2165 cr->cr_uid = pw->pw_uid; 2166 ngroups = NGROUPS + 1; 2167 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 2168 syslog(LOG_ERR, "too many groups"); 2169 /* 2170 * Compress out duplicate. 2171 */ 2172 cr->cr_ngroups = ngroups - 1; 2173 cr->cr_groups[0] = groups[0]; 2174 for (cnt = 2; cnt < ngroups; cnt++) 2175 cr->cr_groups[cnt - 1] = groups[cnt]; 2176 return; 2177 } 2178 /* 2179 * Explicit credential specified as a colon separated list: 2180 * uid:gid:gid:... 2181 */ 2182 if (pw != NULL) 2183 cr->cr_uid = pw->pw_uid; 2184 else if (isdigit(*name) || *name == '-') 2185 cr->cr_uid = atoi(name); 2186 else { 2187 syslog(LOG_ERR, "unknown user: %s", name); 2188 return; 2189 } 2190 cr->cr_ngroups = 0; 2191 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 2192 name = strsep(&names, ":"); 2193 if (isdigit(*name) || *name == '-') { 2194 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 2195 } else { 2196 if ((gr = getgrnam(name)) == NULL) { 2197 syslog(LOG_ERR, "unknown group: %s", name); 2198 continue; 2199 } 2200 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 2201 } 2202 } 2203 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 2204 syslog(LOG_ERR, "too many groups"); 2205} 2206 2207#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 2208/* 2209 * Routines that maintain the remote mounttab 2210 */ 2211void 2212get_mountlist() 2213{ 2214 struct mountlist *mlp, **mlpp; 2215 char *host, *dirp, *cp; 2216 char str[STRSIZ]; 2217 FILE *mlfile; 2218 2219 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 2220 if (errno == ENOENT) 2221 return; 2222 else { 2223 syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 2224 return; 2225 } 2226 } 2227 mlpp = &mlhead; 2228 while (fgets(str, STRSIZ, mlfile) != NULL) { 2229 cp = str; 2230 host = strsep(&cp, " \t\n"); 2231 dirp = strsep(&cp, " \t\n"); 2232 if (host == NULL || dirp == NULL) 2233 continue; 2234 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2235 if (mlp == (struct mountlist *)NULL) 2236 out_of_mem(); 2237 strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 2238 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2239 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2240 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2241 mlp->ml_next = (struct mountlist *)NULL; 2242 *mlpp = mlp; 2243 mlpp = &mlp->ml_next; 2244 } 2245 fclose(mlfile); 2246} 2247 2248void 2249del_mlist(char *hostp, char *dirp) 2250{ 2251 struct mountlist *mlp, **mlpp; 2252 struct mountlist *mlp2; 2253 FILE *mlfile; 2254 int fnd = 0; 2255 2256 mlpp = &mlhead; 2257 mlp = mlhead; 2258 while (mlp) { 2259 if (!strcmp(mlp->ml_host, hostp) && 2260 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 2261 fnd = 1; 2262 mlp2 = mlp; 2263 *mlpp = mlp = mlp->ml_next; 2264 free((caddr_t)mlp2); 2265 } else { 2266 mlpp = &mlp->ml_next; 2267 mlp = mlp->ml_next; 2268 } 2269 } 2270 if (fnd) { 2271 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 2272 syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 2273 return; 2274 } 2275 mlp = mlhead; 2276 while (mlp) { 2277 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2278 mlp = mlp->ml_next; 2279 } 2280 fclose(mlfile); 2281 } 2282} 2283 2284void 2285add_mlist(hostp, dirp) 2286 char *hostp, *dirp; 2287{ 2288 struct mountlist *mlp, **mlpp; 2289 FILE *mlfile; 2290 2291 mlpp = &mlhead; 2292 mlp = mlhead; 2293 while (mlp) { 2294 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 2295 return; 2296 mlpp = &mlp->ml_next; 2297 mlp = mlp->ml_next; 2298 } 2299 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2300 if (mlp == (struct mountlist *)NULL) 2301 out_of_mem(); 2302 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 2303 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2304 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2305 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2306 mlp->ml_next = (struct mountlist *)NULL; 2307 *mlpp = mlp; 2308 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 2309 syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 2310 return; 2311 } 2312 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2313 fclose(mlfile); 2314} 2315 2316/* 2317 * Free up a group list. 2318 */ 2319void 2320free_grp(grp) 2321 struct grouplist *grp; 2322{ 2323 if (grp->gr_type == GT_HOST) { 2324 if (grp->gr_ptr.gt_addrinfo != NULL) 2325 freeaddrinfo(grp->gr_ptr.gt_addrinfo); 2326 } else if (grp->gr_type == GT_NET) { 2327 if (grp->gr_ptr.gt_net.nt_name) 2328 free(grp->gr_ptr.gt_net.nt_name); 2329 } 2330 free((caddr_t)grp); 2331} 2332 2333#ifdef DEBUG 2334void 2335SYSLOG(int pri, const char *fmt, ...) 2336{ 2337 va_list ap; 2338 2339 va_start(ap, fmt); 2340 vfprintf(stderr, fmt, ap); 2341 va_end(ap); 2342} 2343#endif /* DEBUG */ 2344 2345/* 2346 * Check options for consistency. 2347 */ 2348int 2349check_options(dp) 2350 struct dirlist *dp; 2351{ 2352 2353 if (dp == (struct dirlist *)NULL) 2354 return (1); 2355 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 2356 syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 2357 return (1); 2358 } 2359 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 2360 syslog(LOG_ERR, "-mask requires -network"); 2361 return (1); 2362 } 2363 if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 2364 syslog(LOG_ERR, "-network requires mask specification"); 2365 return (1); 2366 } 2367 if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 2368 syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 2369 return (1); 2370 } 2371 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 2372 syslog(LOG_ERR, "-alldirs has multiple directories"); 2373 return (1); 2374 } 2375 return (0); 2376} 2377 2378/* 2379 * Check an absolute directory path for any symbolic links. Return true 2380 */ 2381int 2382check_dirpath(dirp) 2383 char *dirp; 2384{ 2385 char *cp; 2386 int ret = 1; 2387 struct stat sb; 2388 2389 cp = dirp + 1; 2390 while (*cp && ret) { 2391 if (*cp == '/') { 2392 *cp = '\0'; 2393 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2394 ret = 0; 2395 *cp = '/'; 2396 } 2397 cp++; 2398 } 2399 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2400 ret = 0; 2401 return (ret); 2402} 2403 2404/* 2405 * Make a netmask according to the specified prefix length. The ss_family 2406 * and other non-address fields must be initialised before calling this. 2407 */ 2408int 2409makemask(struct sockaddr_storage *ssp, int bitlen) 2410{ 2411 u_char *p; 2412 int bits, i, len; 2413 2414 if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 2415 return (-1); 2416 if (bitlen > len * CHAR_BIT) 2417 return (-1); 2418 2419 for (i = 0; i < len; i++) { 2420 bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 2421 *p++ = (1 << bits) - 1; 2422 bitlen -= bits; 2423 } 2424 return 0; 2425} 2426 2427/* 2428 * Check that the sockaddr is a valid netmask. Returns 0 if the mask 2429 * is acceptable (i.e. of the form 1...10....0). 2430 */ 2431int 2432checkmask(struct sockaddr *sa) 2433{ 2434 u_char *mask; 2435 int i, len; 2436 2437 if ((mask = sa_rawaddr(sa, &len)) == NULL) 2438 return (-1); 2439 2440 for (i = 0; i < len; i++) 2441 if (mask[i] != 0xff) 2442 break; 2443 if (i < len) { 2444 if (~mask[i] & (u_char)(~mask[i] + 1)) 2445 return (-1); 2446 i++; 2447 } 2448 for (; i < len; i++) 2449 if (mask[i] != 0) 2450 return (-1); 2451 return (0); 2452} 2453 2454/* 2455 * Compare two sockaddrs according to a specified mask. Return zero if 2456 * `sa1' matches `sa2' when filtered by the netmask in `samask'. 2457 * If samask is NULL, perform a full comparision. 2458 */ 2459int 2460sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 2461{ 2462 unsigned char *p1, *p2, *mask; 2463 int len, i; 2464 2465 if (sa1->sa_family != sa2->sa_family || 2466 (p1 = sa_rawaddr(sa1, &len)) == NULL || 2467 (p2 = sa_rawaddr(sa2, NULL)) == NULL) 2468 return (1); 2469 2470 switch (sa1->sa_family) { 2471 case AF_INET6: 2472 if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 2473 ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 2474 return (1); 2475 break; 2476 } 2477 2478 /* Simple binary comparison if no mask specified. */ 2479 if (samask == NULL) 2480 return (memcmp(p1, p2, len)); 2481 2482 /* Set up the mask, and do a mask-based comparison. */ 2483 if (sa1->sa_family != samask->sa_family || 2484 (mask = sa_rawaddr(samask, NULL)) == NULL) 2485 return (1); 2486 2487 for (i = 0; i < len; i++) 2488 if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 2489 return (1); 2490 return (0); 2491} 2492 2493/* 2494 * Return a pointer to the part of the sockaddr that contains the 2495 * raw address, and set *nbytes to its length in bytes. Returns 2496 * NULL if the address family is unknown. 2497 */ 2498void * 2499sa_rawaddr(struct sockaddr *sa, int *nbytes) { 2500 void *p; 2501 int len; 2502 2503 switch (sa->sa_family) { 2504 case AF_INET: 2505 len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 2506 p = &((struct sockaddr_in *)sa)->sin_addr; 2507 break; 2508 case AF_INET6: 2509 len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 2510 p = &((struct sockaddr_in6 *)sa)->sin6_addr; 2511 break; 2512 default: 2513 p = NULL; 2514 len = 0; 2515 } 2516 2517 if (nbytes != NULL) 2518 *nbytes = len; 2519 return (p); 2520} 2521 2522void 2523huphandler(int sig) 2524{ 2525 got_sighup = 1; 2526} 2527 2528void terminate(sig) 2529int sig; 2530{ 2531 pidfile_remove(pfh); 2532 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 2533 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 2534 exit (0); 2535}
| 1988} 1989 1990/* 1991 * Translate a net address. 1992 * 1993 * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 1994 */ 1995int 1996get_net(cp, net, maskflg) 1997 char *cp; 1998 struct netmsk *net; 1999 int maskflg; 2000{ 2001 struct netent *np = NULL; 2002 char *name, *p, *prefp; 2003 struct sockaddr_in sin; 2004 struct sockaddr *sa = NULL; 2005 struct addrinfo hints, *ai = NULL; 2006 char netname[NI_MAXHOST]; 2007 long preflen; 2008 2009 p = prefp = NULL; 2010 if ((opt_flags & OP_MASKLEN) && !maskflg) { 2011 p = strchr(cp, '/'); 2012 *p = '\0'; 2013 prefp = p + 1; 2014 } 2015 2016 /* 2017 * Check for a numeric address first. We wish to avoid 2018 * possible DNS lookups in getnetbyname(). 2019 */ 2020 if (isxdigit(*cp) || *cp == ':') { 2021 memset(&hints, 0, sizeof hints); 2022 /* Ensure the mask and the network have the same family. */ 2023 if (maskflg && (opt_flags & OP_NET)) 2024 hints.ai_family = net->nt_net.ss_family; 2025 else if (!maskflg && (opt_flags & OP_HAVEMASK)) 2026 hints.ai_family = net->nt_mask.ss_family; 2027 else 2028 hints.ai_family = AF_UNSPEC; 2029 hints.ai_flags = AI_NUMERICHOST; 2030 if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 2031 sa = ai->ai_addr; 2032 if (sa != NULL && ai->ai_family == AF_INET) { 2033 /* 2034 * The address in `cp' is really a network address, so 2035 * use inet_network() to re-interpret this correctly. 2036 * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 2037 */ 2038 bzero(&sin, sizeof sin); 2039 sin.sin_family = AF_INET; 2040 sin.sin_len = sizeof sin; 2041 sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 2042 if (debug) 2043 fprintf(stderr, "get_net: v4 addr %s\n", 2044 inet_ntoa(sin.sin_addr)); 2045 sa = (struct sockaddr *)&sin; 2046 } 2047 } 2048 if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 2049 bzero(&sin, sizeof sin); 2050 sin.sin_family = AF_INET; 2051 sin.sin_len = sizeof sin; 2052 sin.sin_addr = inet_makeaddr(np->n_net, 0); 2053 sa = (struct sockaddr *)&sin; 2054 } 2055 if (sa == NULL) 2056 goto fail; 2057 2058 if (maskflg) { 2059 /* The specified sockaddr is a mask. */ 2060 if (checkmask(sa) != 0) 2061 goto fail; 2062 bcopy(sa, &net->nt_mask, sa->sa_len); 2063 opt_flags |= OP_HAVEMASK; 2064 } else { 2065 /* The specified sockaddr is a network address. */ 2066 bcopy(sa, &net->nt_net, sa->sa_len); 2067 2068 /* Get a network name for the export list. */ 2069 if (np) { 2070 name = np->n_name; 2071 } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2072 NULL, 0, NI_NUMERICHOST) == 0) { 2073 name = netname; 2074 } else { 2075 goto fail; 2076 } 2077 if ((net->nt_name = strdup(name)) == NULL) 2078 out_of_mem(); 2079 2080 /* 2081 * Extract a mask from either a "/<masklen>" suffix, or 2082 * from the class of an IPv4 address. 2083 */ 2084 if (opt_flags & OP_MASKLEN) { 2085 preflen = strtol(prefp, NULL, 10); 2086 if (preflen < 0L || preflen == LONG_MAX) 2087 goto fail; 2088 bcopy(sa, &net->nt_mask, sa->sa_len); 2089 if (makemask(&net->nt_mask, (int)preflen) != 0) 2090 goto fail; 2091 opt_flags |= OP_HAVEMASK; 2092 *p = '/'; 2093 } else if (sa->sa_family == AF_INET && 2094 (opt_flags & OP_MASK) == 0) { 2095 in_addr_t addr; 2096 2097 addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 2098 if (IN_CLASSA(addr)) 2099 preflen = 8; 2100 else if (IN_CLASSB(addr)) 2101 preflen = 16; 2102 else if (IN_CLASSC(addr)) 2103 preflen = 24; 2104 else if (IN_CLASSD(addr)) 2105 preflen = 28; 2106 else 2107 preflen = 32; /* XXX */ 2108 2109 bcopy(sa, &net->nt_mask, sa->sa_len); 2110 makemask(&net->nt_mask, (int)preflen); 2111 opt_flags |= OP_HAVEMASK; 2112 } 2113 } 2114 2115 if (ai) 2116 freeaddrinfo(ai); 2117 return 0; 2118 2119fail: 2120 if (ai) 2121 freeaddrinfo(ai); 2122 return 1; 2123} 2124 2125/* 2126 * Parse out the next white space separated field 2127 */ 2128void 2129nextfield(cp, endcp) 2130 char **cp; 2131 char **endcp; 2132{ 2133 char *p; 2134 2135 p = *cp; 2136 while (*p == ' ' || *p == '\t') 2137 p++; 2138 if (*p == '\n' || *p == '\0') 2139 *cp = *endcp = p; 2140 else { 2141 *cp = p++; 2142 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 2143 p++; 2144 *endcp = p; 2145 } 2146} 2147 2148/* 2149 * Get an exports file line. Skip over blank lines and handle line 2150 * continuations. 2151 */ 2152int 2153get_line() 2154{ 2155 char *p, *cp; 2156 size_t len; 2157 int totlen, cont_line; 2158 2159 /* 2160 * Loop around ignoring blank lines and getting all continuation lines. 2161 */ 2162 p = line; 2163 totlen = 0; 2164 do { 2165 if ((p = fgetln(exp_file, &len)) == NULL) 2166 return (0); 2167 cp = p + len - 1; 2168 cont_line = 0; 2169 while (cp >= p && 2170 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 2171 if (*cp == '\\') 2172 cont_line = 1; 2173 cp--; 2174 len--; 2175 } 2176 if (cont_line) { 2177 *++cp = ' '; 2178 len++; 2179 } 2180 if (linesize < len + totlen + 1) { 2181 linesize = len + totlen + 1; 2182 line = realloc(line, linesize); 2183 if (line == NULL) 2184 out_of_mem(); 2185 } 2186 memcpy(line + totlen, p, len); 2187 totlen += len; 2188 line[totlen] = '\0'; 2189 } while (totlen == 0 || cont_line); 2190 return (1); 2191} 2192 2193/* 2194 * Parse a description of a credential. 2195 */ 2196void 2197parsecred(namelist, cr) 2198 char *namelist; 2199 struct xucred *cr; 2200{ 2201 char *name; 2202 int cnt; 2203 char *names; 2204 struct passwd *pw; 2205 struct group *gr; 2206 gid_t groups[NGROUPS + 1]; 2207 int ngroups; 2208 2209 cr->cr_version = XUCRED_VERSION; 2210 /* 2211 * Set up the unprivileged user. 2212 */ 2213 cr->cr_uid = -2; 2214 cr->cr_groups[0] = -2; 2215 cr->cr_ngroups = 1; 2216 /* 2217 * Get the user's password table entry. 2218 */ 2219 names = strsep(&namelist, " \t\n"); 2220 name = strsep(&names, ":"); 2221 if (isdigit(*name) || *name == '-') 2222 pw = getpwuid(atoi(name)); 2223 else 2224 pw = getpwnam(name); 2225 /* 2226 * Credentials specified as those of a user. 2227 */ 2228 if (names == NULL) { 2229 if (pw == NULL) { 2230 syslog(LOG_ERR, "unknown user: %s", name); 2231 return; 2232 } 2233 cr->cr_uid = pw->pw_uid; 2234 ngroups = NGROUPS + 1; 2235 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 2236 syslog(LOG_ERR, "too many groups"); 2237 /* 2238 * Compress out duplicate. 2239 */ 2240 cr->cr_ngroups = ngroups - 1; 2241 cr->cr_groups[0] = groups[0]; 2242 for (cnt = 2; cnt < ngroups; cnt++) 2243 cr->cr_groups[cnt - 1] = groups[cnt]; 2244 return; 2245 } 2246 /* 2247 * Explicit credential specified as a colon separated list: 2248 * uid:gid:gid:... 2249 */ 2250 if (pw != NULL) 2251 cr->cr_uid = pw->pw_uid; 2252 else if (isdigit(*name) || *name == '-') 2253 cr->cr_uid = atoi(name); 2254 else { 2255 syslog(LOG_ERR, "unknown user: %s", name); 2256 return; 2257 } 2258 cr->cr_ngroups = 0; 2259 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 2260 name = strsep(&names, ":"); 2261 if (isdigit(*name) || *name == '-') { 2262 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 2263 } else { 2264 if ((gr = getgrnam(name)) == NULL) { 2265 syslog(LOG_ERR, "unknown group: %s", name); 2266 continue; 2267 } 2268 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 2269 } 2270 } 2271 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 2272 syslog(LOG_ERR, "too many groups"); 2273} 2274 2275#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 2276/* 2277 * Routines that maintain the remote mounttab 2278 */ 2279void 2280get_mountlist() 2281{ 2282 struct mountlist *mlp, **mlpp; 2283 char *host, *dirp, *cp; 2284 char str[STRSIZ]; 2285 FILE *mlfile; 2286 2287 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 2288 if (errno == ENOENT) 2289 return; 2290 else { 2291 syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 2292 return; 2293 } 2294 } 2295 mlpp = &mlhead; 2296 while (fgets(str, STRSIZ, mlfile) != NULL) { 2297 cp = str; 2298 host = strsep(&cp, " \t\n"); 2299 dirp = strsep(&cp, " \t\n"); 2300 if (host == NULL || dirp == NULL) 2301 continue; 2302 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2303 if (mlp == (struct mountlist *)NULL) 2304 out_of_mem(); 2305 strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 2306 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2307 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2308 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2309 mlp->ml_next = (struct mountlist *)NULL; 2310 *mlpp = mlp; 2311 mlpp = &mlp->ml_next; 2312 } 2313 fclose(mlfile); 2314} 2315 2316void 2317del_mlist(char *hostp, char *dirp) 2318{ 2319 struct mountlist *mlp, **mlpp; 2320 struct mountlist *mlp2; 2321 FILE *mlfile; 2322 int fnd = 0; 2323 2324 mlpp = &mlhead; 2325 mlp = mlhead; 2326 while (mlp) { 2327 if (!strcmp(mlp->ml_host, hostp) && 2328 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 2329 fnd = 1; 2330 mlp2 = mlp; 2331 *mlpp = mlp = mlp->ml_next; 2332 free((caddr_t)mlp2); 2333 } else { 2334 mlpp = &mlp->ml_next; 2335 mlp = mlp->ml_next; 2336 } 2337 } 2338 if (fnd) { 2339 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 2340 syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 2341 return; 2342 } 2343 mlp = mlhead; 2344 while (mlp) { 2345 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2346 mlp = mlp->ml_next; 2347 } 2348 fclose(mlfile); 2349 } 2350} 2351 2352void 2353add_mlist(hostp, dirp) 2354 char *hostp, *dirp; 2355{ 2356 struct mountlist *mlp, **mlpp; 2357 FILE *mlfile; 2358 2359 mlpp = &mlhead; 2360 mlp = mlhead; 2361 while (mlp) { 2362 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 2363 return; 2364 mlpp = &mlp->ml_next; 2365 mlp = mlp->ml_next; 2366 } 2367 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2368 if (mlp == (struct mountlist *)NULL) 2369 out_of_mem(); 2370 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 2371 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2372 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2373 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2374 mlp->ml_next = (struct mountlist *)NULL; 2375 *mlpp = mlp; 2376 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 2377 syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 2378 return; 2379 } 2380 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2381 fclose(mlfile); 2382} 2383 2384/* 2385 * Free up a group list. 2386 */ 2387void 2388free_grp(grp) 2389 struct grouplist *grp; 2390{ 2391 if (grp->gr_type == GT_HOST) { 2392 if (grp->gr_ptr.gt_addrinfo != NULL) 2393 freeaddrinfo(grp->gr_ptr.gt_addrinfo); 2394 } else if (grp->gr_type == GT_NET) { 2395 if (grp->gr_ptr.gt_net.nt_name) 2396 free(grp->gr_ptr.gt_net.nt_name); 2397 } 2398 free((caddr_t)grp); 2399} 2400 2401#ifdef DEBUG 2402void 2403SYSLOG(int pri, const char *fmt, ...) 2404{ 2405 va_list ap; 2406 2407 va_start(ap, fmt); 2408 vfprintf(stderr, fmt, ap); 2409 va_end(ap); 2410} 2411#endif /* DEBUG */ 2412 2413/* 2414 * Check options for consistency. 2415 */ 2416int 2417check_options(dp) 2418 struct dirlist *dp; 2419{ 2420 2421 if (dp == (struct dirlist *)NULL) 2422 return (1); 2423 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 2424 syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 2425 return (1); 2426 } 2427 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 2428 syslog(LOG_ERR, "-mask requires -network"); 2429 return (1); 2430 } 2431 if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 2432 syslog(LOG_ERR, "-network requires mask specification"); 2433 return (1); 2434 } 2435 if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 2436 syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 2437 return (1); 2438 } 2439 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 2440 syslog(LOG_ERR, "-alldirs has multiple directories"); 2441 return (1); 2442 } 2443 return (0); 2444} 2445 2446/* 2447 * Check an absolute directory path for any symbolic links. Return true 2448 */ 2449int 2450check_dirpath(dirp) 2451 char *dirp; 2452{ 2453 char *cp; 2454 int ret = 1; 2455 struct stat sb; 2456 2457 cp = dirp + 1; 2458 while (*cp && ret) { 2459 if (*cp == '/') { 2460 *cp = '\0'; 2461 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2462 ret = 0; 2463 *cp = '/'; 2464 } 2465 cp++; 2466 } 2467 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2468 ret = 0; 2469 return (ret); 2470} 2471 2472/* 2473 * Make a netmask according to the specified prefix length. The ss_family 2474 * and other non-address fields must be initialised before calling this. 2475 */ 2476int 2477makemask(struct sockaddr_storage *ssp, int bitlen) 2478{ 2479 u_char *p; 2480 int bits, i, len; 2481 2482 if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 2483 return (-1); 2484 if (bitlen > len * CHAR_BIT) 2485 return (-1); 2486 2487 for (i = 0; i < len; i++) { 2488 bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 2489 *p++ = (1 << bits) - 1; 2490 bitlen -= bits; 2491 } 2492 return 0; 2493} 2494 2495/* 2496 * Check that the sockaddr is a valid netmask. Returns 0 if the mask 2497 * is acceptable (i.e. of the form 1...10....0). 2498 */ 2499int 2500checkmask(struct sockaddr *sa) 2501{ 2502 u_char *mask; 2503 int i, len; 2504 2505 if ((mask = sa_rawaddr(sa, &len)) == NULL) 2506 return (-1); 2507 2508 for (i = 0; i < len; i++) 2509 if (mask[i] != 0xff) 2510 break; 2511 if (i < len) { 2512 if (~mask[i] & (u_char)(~mask[i] + 1)) 2513 return (-1); 2514 i++; 2515 } 2516 for (; i < len; i++) 2517 if (mask[i] != 0) 2518 return (-1); 2519 return (0); 2520} 2521 2522/* 2523 * Compare two sockaddrs according to a specified mask. Return zero if 2524 * `sa1' matches `sa2' when filtered by the netmask in `samask'. 2525 * If samask is NULL, perform a full comparision. 2526 */ 2527int 2528sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 2529{ 2530 unsigned char *p1, *p2, *mask; 2531 int len, i; 2532 2533 if (sa1->sa_family != sa2->sa_family || 2534 (p1 = sa_rawaddr(sa1, &len)) == NULL || 2535 (p2 = sa_rawaddr(sa2, NULL)) == NULL) 2536 return (1); 2537 2538 switch (sa1->sa_family) { 2539 case AF_INET6: 2540 if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 2541 ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 2542 return (1); 2543 break; 2544 } 2545 2546 /* Simple binary comparison if no mask specified. */ 2547 if (samask == NULL) 2548 return (memcmp(p1, p2, len)); 2549 2550 /* Set up the mask, and do a mask-based comparison. */ 2551 if (sa1->sa_family != samask->sa_family || 2552 (mask = sa_rawaddr(samask, NULL)) == NULL) 2553 return (1); 2554 2555 for (i = 0; i < len; i++) 2556 if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 2557 return (1); 2558 return (0); 2559} 2560 2561/* 2562 * Return a pointer to the part of the sockaddr that contains the 2563 * raw address, and set *nbytes to its length in bytes. Returns 2564 * NULL if the address family is unknown. 2565 */ 2566void * 2567sa_rawaddr(struct sockaddr *sa, int *nbytes) { 2568 void *p; 2569 int len; 2570 2571 switch (sa->sa_family) { 2572 case AF_INET: 2573 len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 2574 p = &((struct sockaddr_in *)sa)->sin_addr; 2575 break; 2576 case AF_INET6: 2577 len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 2578 p = &((struct sockaddr_in6 *)sa)->sin6_addr; 2579 break; 2580 default: 2581 p = NULL; 2582 len = 0; 2583 } 2584 2585 if (nbytes != NULL) 2586 *nbytes = len; 2587 return (p); 2588} 2589 2590void 2591huphandler(int sig) 2592{ 2593 got_sighup = 1; 2594} 2595 2596void terminate(sig) 2597int sig; 2598{ 2599 pidfile_remove(pfh); 2600 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 2601 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 2602 exit (0); 2603}
|