mountd.c revision 168684
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1989, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * This code is derived from software contributed to Berkeley by 61558Srgrimes * Herb Hasler and Rick Macklem at The University of Guelph. 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 4. Neither the name of the University nor the names of its contributors 171558Srgrimes * may be used to endorse or promote products derived from this software 181558Srgrimes * without specific prior written permission. 191558Srgrimes * 201558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301558Srgrimes * SUCH DAMAGE. 311558Srgrimes */ 321558Srgrimes 331558Srgrimes#ifndef lint 3437663Scharnierstatic const char copyright[] = 351558Srgrimes"@(#) Copyright (c) 1989, 1993\n\ 361558Srgrimes The Regents of the University of California. All rights reserved.\n"; 372999Swollman#endif /*not lint*/ 381558Srgrimes 39105267Scharnier#if 0 401558Srgrimes#ifndef lint 4137663Scharnierstatic char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 42105267Scharnier#endif /*not lint*/ 4337663Scharnier#endif 441558Srgrimes 45105267Scharnier#include <sys/cdefs.h> 46105267Scharnier__FBSDID("$FreeBSD: head/usr.sbin/mountd/mountd.c 168684 2007-04-13 10:25:49Z pjd $"); 47105267Scharnier 481558Srgrimes#include <sys/param.h> 491558Srgrimes#include <sys/mount.h> 5074462Salfred#include <sys/fcntl.h> 511558Srgrimes#include <sys/stat.h> 521558Srgrimes#include <sys/syslog.h> 5324330Sguido#include <sys/sysctl.h> 5496622Siedowse#include <sys/linker.h> 5596622Siedowse#include <sys/module.h> 561558Srgrimes 571558Srgrimes#include <rpc/rpc.h> 58109363Smbr#include <rpc/rpc_com.h> 591558Srgrimes#include <rpc/pmap_clnt.h> 6074462Salfred#include <rpc/pmap_prot.h> 6174462Salfred#include <rpcsvc/mount.h> 621558Srgrimes#include <nfs/rpcv2.h> 639336Sdfr#include <nfs/nfsproto.h> 6483653Speter#include <nfsserver/nfs.h> 651558Srgrimes 661558Srgrimes#include <arpa/inet.h> 671558Srgrimes 681558Srgrimes#include <ctype.h> 6937663Scharnier#include <err.h> 701558Srgrimes#include <errno.h> 711558Srgrimes#include <grp.h> 72149433Spjd#include <libutil.h> 73103949Smike#include <limits.h> 741558Srgrimes#include <netdb.h> 751558Srgrimes#include <pwd.h> 761558Srgrimes#include <signal.h> 771558Srgrimes#include <stdio.h> 781558Srgrimes#include <stdlib.h> 791558Srgrimes#include <string.h> 801558Srgrimes#include <unistd.h> 811558Srgrimes#include "pathnames.h" 82158857Srodrigc#include "mntopts.h" 831558Srgrimes 841558Srgrimes#ifdef DEBUG 851558Srgrimes#include <stdarg.h> 861558Srgrimes#endif 871558Srgrimes 881558Srgrimes/* 891558Srgrimes * Structures for keeping the mount list and export list 901558Srgrimes */ 911558Srgrimesstruct mountlist { 921558Srgrimes struct mountlist *ml_next; 931558Srgrimes char ml_host[RPCMNT_NAMELEN+1]; 941558Srgrimes char ml_dirp[RPCMNT_PATHLEN+1]; 951558Srgrimes}; 961558Srgrimes 971558Srgrimesstruct dirlist { 981558Srgrimes struct dirlist *dp_left; 991558Srgrimes struct dirlist *dp_right; 1001558Srgrimes int dp_flag; 1011558Srgrimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 1021558Srgrimes char dp_dirp[1]; /* Actually malloc'd to size of dir */ 1031558Srgrimes}; 1041558Srgrimes/* dp_flag bits */ 1051558Srgrimes#define DP_DEFSET 0x1 1069336Sdfr#define DP_HOSTSET 0x2 1071558Srgrimes 1081558Srgrimesstruct exportlist { 1091558Srgrimes struct exportlist *ex_next; 1101558Srgrimes struct dirlist *ex_dirl; 1111558Srgrimes struct dirlist *ex_defdir; 1121558Srgrimes int ex_flag; 1131558Srgrimes fsid_t ex_fs; 1141558Srgrimes char *ex_fsdir; 11527447Sdfr char *ex_indexfile; 1161558Srgrimes}; 1171558Srgrimes/* ex_flag bits */ 1181558Srgrimes#define EX_LINKED 0x1 1191558Srgrimes 1201558Srgrimesstruct netmsk { 12174462Salfred struct sockaddr_storage nt_net; 12275801Siedowse struct sockaddr_storage nt_mask; 12342144Sdfr char *nt_name; 1241558Srgrimes}; 1251558Srgrimes 1261558Srgrimesunion grouptypes { 12774462Salfred struct addrinfo *gt_addrinfo; 1281558Srgrimes struct netmsk gt_net; 1291558Srgrimes}; 1301558Srgrimes 1311558Srgrimesstruct grouplist { 1321558Srgrimes int gr_type; 1331558Srgrimes union grouptypes gr_ptr; 1341558Srgrimes struct grouplist *gr_next; 1351558Srgrimes}; 1361558Srgrimes/* Group types */ 1371558Srgrimes#define GT_NULL 0x0 1381558Srgrimes#define GT_HOST 0x1 1391558Srgrimes#define GT_NET 0x2 14075641Siedowse#define GT_DEFAULT 0x3 1417401Swpaul#define GT_IGNORE 0x5 1421558Srgrimes 1431558Srgrimesstruct hostlist { 1449336Sdfr int ht_flag; /* Uses DP_xx bits */ 1451558Srgrimes struct grouplist *ht_grp; 1461558Srgrimes struct hostlist *ht_next; 1471558Srgrimes}; 1481558Srgrimes 1499336Sdfrstruct fhreturn { 1509336Sdfr int fhr_flag; 1519336Sdfr int fhr_vers; 1529336Sdfr nfsfh_t fhr_fh; 1539336Sdfr}; 1549336Sdfr 1551558Srgrimes/* Global defs */ 15692882Simpchar *add_expdir(struct dirlist **, char *, int); 15792882Simpvoid add_dlist(struct dirlist **, struct dirlist *, 15892882Simp struct grouplist *, int); 15992882Simpvoid add_mlist(char *, char *); 16092882Simpint check_dirpath(char *); 16192882Simpint check_options(struct dirlist *); 16275801Siedowseint checkmask(struct sockaddr *sa); 16392882Simpint chk_host(struct dirlist *, struct sockaddr *, int *, int *); 16475635Siedowsevoid del_mlist(char *hostp, char *dirp); 16592882Simpstruct dirlist *dirp_search(struct dirlist *, char *); 16692882Simpint do_mount(struct exportlist *, struct grouplist *, int, 16792882Simp struct xucred *, char *, int, struct statfs *); 16892882Simpint do_opt(char **, char **, struct exportlist *, struct grouplist *, 16992882Simp int *, int *, struct xucred *); 17092882Simpstruct exportlist *ex_search(fsid_t *); 17192882Simpstruct exportlist *get_exp(void); 17292882Simpvoid free_dir(struct dirlist *); 17392882Simpvoid free_exp(struct exportlist *); 17492882Simpvoid free_grp(struct grouplist *); 17592882Simpvoid free_host(struct hostlist *); 17692882Simpvoid get_exportlist(void); 17792882Simpint get_host(char *, struct grouplist *, struct grouplist *); 17892882Simpstruct hostlist *get_ht(void); 17992882Simpint get_line(void); 18092882Simpvoid get_mountlist(void); 18192882Simpint get_net(char *, struct netmsk *, int); 18292882Simpvoid getexp_err(struct exportlist *, struct grouplist *); 18392882Simpstruct grouplist *get_grp(void); 18492882Simpvoid hang_dirp(struct dirlist *, struct grouplist *, 18592882Simp struct exportlist *, int); 18675754Siedowsevoid huphandler(int sig); 18775801Siedowseint makemask(struct sockaddr_storage *ssp, int bitlen); 18892882Simpvoid mntsrv(struct svc_req *, SVCXPRT *); 18992882Simpvoid nextfield(char **, char **); 19092882Simpvoid out_of_mem(void); 19192882Simpvoid parsecred(char *, struct xucred *); 192100117Salfredint put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 19375801Siedowsevoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 19475801Siedowseint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 19575801Siedowse struct sockaddr *samask); 19692882Simpint scan_tree(struct dirlist *, struct sockaddr *); 19792882Simpstatic void usage(void); 19892882Simpint xdr_dir(XDR *, char *); 19992882Simpint xdr_explist(XDR *, caddr_t); 200100117Salfredint xdr_explist_brief(XDR *, caddr_t); 20192882Simpint xdr_fhs(XDR *, caddr_t); 20292882Simpint xdr_mlist(XDR *, caddr_t); 20392882Simpvoid terminate(int); 2041558Srgrimes 2051558Srgrimesstruct exportlist *exphead; 2061558Srgrimesstruct mountlist *mlhead; 2071558Srgrimesstruct grouplist *grphead; 208166440Spjdchar *exnames_default[2] = { _PATH_EXPORTS, NULL }; 209166440Spjdchar **exnames; 21072650Sgreenstruct xucred def_anon = { 21191354Sdd XUCRED_VERSION, 21272650Sgreen (uid_t)-2, 2131558Srgrimes 1, 21472650Sgreen { (gid_t)-2 }, 21572650Sgreen NULL 2161558Srgrimes}; 21725087Sdfrint force_v2 = 0; 2189336Sdfrint resvport_only = 1; 2199336Sdfrint dir_only = 1; 220121767Speterint dolog = 0; 22175754Siedowseint got_sighup = 0; 22274462Salfred 2231558Srgrimesint opt_flags; 22474462Salfredstatic int have_v6 = 1; 22574462Salfred 226149433Spjdstruct pidfh *pfh = NULL; 22775801Siedowse/* Bits for opt_flags above */ 2281558Srgrimes#define OP_MAPROOT 0x01 2291558Srgrimes#define OP_MAPALL 0x02 23083653Speter/* 0x4 free */ 2311558Srgrimes#define OP_MASK 0x08 2321558Srgrimes#define OP_NET 0x10 2331558Srgrimes#define OP_ALLDIRS 0x40 23475801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 235100336Sjoerg#define OP_QUIET 0x100 23674462Salfred#define OP_MASKLEN 0x200 2371558Srgrimes 2381558Srgrimes#ifdef DEBUG 2391558Srgrimesint debug = 1; 24092882Simpvoid SYSLOG(int, const char *, ...) __printflike(2, 3); 2411558Srgrimes#define syslog SYSLOG 2421558Srgrimes#else 2431558Srgrimesint debug = 0; 2441558Srgrimes#endif 2451558Srgrimes 2461558Srgrimes/* 2471558Srgrimes * Mountd server for NFS mount protocol as described in: 2481558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 2491558Srgrimes * The optional arguments are the exports file name 2501558Srgrimes * default: _PATH_EXPORTS 2511558Srgrimes * and "-n" to allow nonroot mount. 2521558Srgrimes */ 2531558Srgrimesint 2541558Srgrimesmain(argc, argv) 2551558Srgrimes int argc; 2561558Srgrimes char **argv; 2571558Srgrimes{ 25875754Siedowse fd_set readfds; 259126572Sbms struct sockaddr_in sin; 260126572Sbms struct sockaddr_in6 sin6; 261126572Sbms char *endptr; 26274462Salfred SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; 26374462Salfred struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 264149433Spjd pid_t otherpid; 26574462Salfred int udpsock, tcpsock, udp6sock, tcp6sock; 26674462Salfred int xcreated = 0, s; 267109363Smbr int maxrec = RPC_MAXDATASIZE; 26874462Salfred int one = 1; 269126572Sbms int c, r; 270126572Sbms in_port_t svcport = 0; 2711558Srgrimes 27275635Siedowse udp6conf = tcp6conf = NULL; 273126643Smarkm udp6sock = tcp6sock = 0; 27475635Siedowse 27574462Salfred /* Check that another mountd isn't already running. */ 276150214Spjd pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 277149433Spjd if (pfh == NULL) { 278149433Spjd if (errno == EEXIST) 279149433Spjd errx(1, "mountd already running, pid: %d.", otherpid); 280149433Spjd warn("cannot open or create pidfile"); 281149433Spjd } 28274462Salfred 28374462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 28474462Salfred if (s < 0) 28574462Salfred have_v6 = 0; 28674462Salfred else 28774462Salfred close(s); 28883687Speter if (modfind("nfsserver") < 0) { 28983687Speter /* Not present in kernel, try loading it */ 29083687Speter if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 29183687Speter errx(1, "NFS server is not available or loadable"); 2922999Swollman } 2932999Swollman 294126572Sbms while ((c = getopt(argc, argv, "2dlnp:r")) != -1) 2951558Srgrimes switch (c) { 29625087Sdfr case '2': 29725087Sdfr force_v2 = 1; 29825087Sdfr break; 2999336Sdfr case 'n': 3009336Sdfr resvport_only = 0; 3019336Sdfr break; 3029336Sdfr case 'r': 3039336Sdfr dir_only = 0; 3049336Sdfr break; 3058688Sphk case 'd': 3068688Sphk debug = debug ? 0 : 1; 3078688Sphk break; 30831656Sguido case 'l': 309121767Speter dolog = 1; 31031656Sguido break; 311126572Sbms case 'p': 312126572Sbms endptr = NULL; 313126572Sbms svcport = (in_port_t)strtoul(optarg, &endptr, 10); 314126572Sbms if (endptr == NULL || *endptr != '\0' || 315126572Sbms svcport == 0 || svcport >= IPPORT_MAX) 316126572Sbms usage(); 317126572Sbms break; 3181558Srgrimes default: 31937663Scharnier usage(); 3201558Srgrimes }; 3211558Srgrimes argc -= optind; 3221558Srgrimes argv += optind; 3231558Srgrimes grphead = (struct grouplist *)NULL; 3241558Srgrimes exphead = (struct exportlist *)NULL; 3251558Srgrimes mlhead = (struct mountlist *)NULL; 326166440Spjd if (argc > 0) 327166440Spjd exnames = argv; 328166440Spjd else 329166440Spjd exnames = exnames_default; 3301558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 3311558Srgrimes if (debug) 33237663Scharnier warnx("getting export list"); 3331558Srgrimes get_exportlist(); 3341558Srgrimes if (debug) 33537663Scharnier warnx("getting mount list"); 3361558Srgrimes get_mountlist(); 3371558Srgrimes if (debug) 33837663Scharnier warnx("here we go"); 3391558Srgrimes if (debug == 0) { 3401558Srgrimes daemon(0, 0); 3411558Srgrimes signal(SIGINT, SIG_IGN); 3421558Srgrimes signal(SIGQUIT, SIG_IGN); 3431558Srgrimes } 34475754Siedowse signal(SIGHUP, huphandler); 34574462Salfred signal(SIGTERM, terminate); 346164394Srodrigc signal(SIGPIPE, SIG_IGN); 347149433Spjd 348149433Spjd pidfile_write(pfh); 349149433Spjd 35074462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 35174462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 35274462Salfred udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 35374462Salfred tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 35474791Salfred udpconf = getnetconfigent("udp"); 35574791Salfred tcpconf = getnetconfigent("tcp"); 356109363Smbr 357109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 358109363Smbr 35974791Salfred if (!have_v6) 36074791Salfred goto skip_v6; 36174462Salfred udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 36274462Salfred tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 36374462Salfred /* 36474462Salfred * We're doing host-based access checks here, so don't allow 36574462Salfred * v4-in-v6 to confuse things. The kernel will disable it 36674462Salfred * by default on NFS sockets too. 36774462Salfred */ 36874462Salfred if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6, 369117684Srwatson IPV6_V6ONLY, &one, sizeof one) < 0) { 37074462Salfred syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 37174462Salfred exit(1); 37274462Salfred } 37374462Salfred if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6, 374117684Srwatson IPV6_V6ONLY, &one, sizeof one) < 0) { 375117684Srwatson syslog(LOG_ERR, "can't disable v4-in-v6 on TCP socket"); 37674462Salfred exit(1); 37774462Salfred } 37874462Salfred udp6conf = getnetconfigent("udp6"); 37974462Salfred tcp6conf = getnetconfigent("tcp6"); 38074791Salfred 38174791Salfredskip_v6: 38224759Sguido if (!resvport_only) { 38383687Speter if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 38483687Speter &resvport_only, sizeof(resvport_only)) != 0 && 38583687Speter errno != ENOENT) { 38624759Sguido syslog(LOG_ERR, "sysctl: %m"); 38724759Sguido exit(1); 38824759Sguido } 38924330Sguido } 390126572Sbms if (svcport != 0) { 391126572Sbms bzero(&sin, sizeof(struct sockaddr_in)); 392126572Sbms sin.sin_len = sizeof(struct sockaddr_in); 393126572Sbms sin.sin_family = AF_INET; 394126572Sbms sin.sin_port = htons(svcport); 395126572Sbms 396126572Sbms bzero(&sin6, sizeof(struct sockaddr_in6)); 397126572Sbms sin6.sin6_len = sizeof(struct sockaddr_in6); 398126572Sbms sin6.sin6_family = AF_INET6; 399126572Sbms sin6.sin6_port = htons(svcport); 400126572Sbms } 40174462Salfred if (udpsock != -1 && udpconf != NULL) { 402126572Sbms if (svcport != 0) { 403126572Sbms r = bindresvport(udpsock, &sin); 404126572Sbms if (r != 0) { 405126572Sbms syslog(LOG_ERR, "bindresvport: %m"); 406126572Sbms exit(1); 407126572Sbms } 408126572Sbms } else 409126572Sbms (void)bindresvport(udpsock, NULL); 41074462Salfred udptransp = svc_dg_create(udpsock, 0, 0); 41174462Salfred if (udptransp != NULL) { 41274462Salfred if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, 41374462Salfred mntsrv, udpconf)) 41474462Salfred syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service"); 41574462Salfred else 41674462Salfred xcreated++; 41774462Salfred if (!force_v2) { 41874462Salfred if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3, 41974462Salfred mntsrv, udpconf)) 42074462Salfred syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service"); 42174462Salfred else 42274462Salfred xcreated++; 42374462Salfred } 42474462Salfred } else 42574462Salfred syslog(LOG_WARNING, "can't create UDP services"); 42674462Salfred 42774462Salfred } 42874462Salfred if (tcpsock != -1 && tcpconf != NULL) { 429126572Sbms if (svcport != 0) { 430126572Sbms r = bindresvport(tcpsock, &sin); 431126572Sbms if (r != 0) { 432126572Sbms syslog(LOG_ERR, "bindresvport: %m"); 433126572Sbms exit(1); 434126572Sbms } 435126572Sbms } else 436126572Sbms (void)bindresvport(tcpsock, NULL); 43774462Salfred listen(tcpsock, SOMAXCONN); 438109363Smbr tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 43974462Salfred if (tcptransp != NULL) { 44074462Salfred if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1, 44174462Salfred mntsrv, tcpconf)) 44274462Salfred syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service"); 44374462Salfred else 44474462Salfred xcreated++; 44574462Salfred if (!force_v2) { 44674462Salfred if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3, 44774462Salfred mntsrv, tcpconf)) 44874462Salfred syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service"); 44974462Salfred else 45074462Salfred xcreated++; 45174462Salfred } 45274462Salfred } else 45374462Salfred syslog(LOG_WARNING, "can't create TCP service"); 45474462Salfred 45574462Salfred } 45674791Salfred if (have_v6 && udp6sock != -1 && udp6conf != NULL) { 457126572Sbms if (svcport != 0) { 458126572Sbms r = bindresvport_sa(udp6sock, 459126572Sbms (struct sockaddr *)&sin6); 460126572Sbms if (r != 0) { 461126572Sbms syslog(LOG_ERR, "bindresvport_sa: %m"); 462126572Sbms exit(1); 463126572Sbms } 464126572Sbms } else 465126572Sbms (void)bindresvport_sa(udp6sock, NULL); 46674462Salfred udp6transp = svc_dg_create(udp6sock, 0, 0); 46774462Salfred if (udp6transp != NULL) { 46874462Salfred if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, 46974462Salfred mntsrv, udp6conf)) 47074462Salfred syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service"); 47174462Salfred else 47274462Salfred xcreated++; 47374462Salfred if (!force_v2) { 47474462Salfred if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3, 47574462Salfred mntsrv, udp6conf)) 47674462Salfred syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service"); 47774462Salfred else 47874462Salfred xcreated++; 47974462Salfred } 48074462Salfred } else 48174462Salfred syslog(LOG_WARNING, "can't create UDP6 service"); 48274462Salfred 48374462Salfred } 48474791Salfred if (have_v6 && tcp6sock != -1 && tcp6conf != NULL) { 485126572Sbms if (svcport != 0) { 486126572Sbms r = bindresvport_sa(tcp6sock, 487126572Sbms (struct sockaddr *)&sin6); 488126572Sbms if (r != 0) { 489126572Sbms syslog(LOG_ERR, "bindresvport_sa: %m"); 490126572Sbms exit(1); 491126572Sbms } 492126572Sbms } else 493126572Sbms (void)bindresvport_sa(tcp6sock, NULL); 49474462Salfred listen(tcp6sock, SOMAXCONN); 495109363Smbr tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 49674462Salfred if (tcp6transp != NULL) { 49774462Salfred if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1, 49874462Salfred mntsrv, tcp6conf)) 49974462Salfred syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service"); 50074462Salfred else 50174462Salfred xcreated++; 50274462Salfred if (!force_v2) { 50374462Salfred if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3, 50474462Salfred mntsrv, tcp6conf)) 50574462Salfred syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service"); 50674462Salfred else 50774462Salfred xcreated++; 50874462Salfred } 50974462Salfred } else 51074462Salfred syslog(LOG_WARNING, "can't create TCP6 service"); 51174462Salfred 51274462Salfred } 51374462Salfred if (xcreated == 0) { 51474462Salfred syslog(LOG_ERR, "could not create any services"); 5151558Srgrimes exit(1); 5161558Srgrimes } 51775754Siedowse 51875754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 51975754Siedowse for (;;) { 52075754Siedowse if (got_sighup) { 52175754Siedowse get_exportlist(); 52275754Siedowse got_sighup = 0; 52375754Siedowse } 52475754Siedowse readfds = svc_fdset; 52575754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 52675754Siedowse case -1: 52775754Siedowse if (errno == EINTR) 52875754Siedowse continue; 52975754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 53075754Siedowse exit(1); 53175754Siedowse case 0: 53275754Siedowse continue; 53375754Siedowse default: 53475754Siedowse svc_getreqset(&readfds); 53575754Siedowse } 53675754Siedowse } 5371558Srgrimes} 5381558Srgrimes 53937663Scharnierstatic void 54037663Scharnierusage() 54137663Scharnier{ 54237663Scharnier fprintf(stderr, 543126572Sbms "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] " 544166440Spjd "[export_file ...]\n"); 54537663Scharnier exit(1); 54637663Scharnier} 54737663Scharnier 5481558Srgrimes/* 5491558Srgrimes * The mount rpc service 5501558Srgrimes */ 5511558Srgrimesvoid 5521558Srgrimesmntsrv(rqstp, transp) 5531558Srgrimes struct svc_req *rqstp; 5541558Srgrimes SVCXPRT *transp; 5551558Srgrimes{ 5561558Srgrimes struct exportlist *ep; 5571558Srgrimes struct dirlist *dp; 5589336Sdfr struct fhreturn fhr; 5591558Srgrimes struct stat stb; 5601558Srgrimes struct statfs fsb; 56174462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 56274462Salfred int lookup_failed = 1; 56374462Salfred struct sockaddr *saddr; 5649336Sdfr u_short sport; 56523681Speter char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 56628911Sguido int bad = 0, defset, hostset; 5679336Sdfr sigset_t sighup_mask; 5681558Srgrimes 5699336Sdfr sigemptyset(&sighup_mask); 5709336Sdfr sigaddset(&sighup_mask, SIGHUP); 57174462Salfred saddr = svc_getrpccaller(transp)->buf; 57274462Salfred switch (saddr->sa_family) { 57374462Salfred case AF_INET6: 57475635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 57574462Salfred break; 57674462Salfred case AF_INET: 57775635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 57874462Salfred break; 57974462Salfred default: 58074462Salfred syslog(LOG_ERR, "request from unknown address family"); 58174462Salfred return; 58274462Salfred } 58374462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 58474462Salfred NULL, 0, 0); 58574462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 58674462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 5871558Srgrimes switch (rqstp->rq_proc) { 5881558Srgrimes case NULLPROC: 589121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 59037663Scharnier syslog(LOG_ERR, "can't send reply"); 5911558Srgrimes return; 5921558Srgrimes case RPCMNT_MOUNT: 5939336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 59431656Sguido syslog(LOG_NOTICE, 59531656Sguido "mount request from %s from unprivileged port", 59674462Salfred numerichost); 5971558Srgrimes svcerr_weakauth(transp); 5981558Srgrimes return; 5991558Srgrimes } 600121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 60131656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 60274462Salfred numerichost); 6031558Srgrimes svcerr_decode(transp); 6041558Srgrimes return; 6051558Srgrimes } 6061558Srgrimes 6071558Srgrimes /* 6081558Srgrimes * Get the real pathname and make sure it is a directory 6099336Sdfr * or a regular file if the -r option was specified 6109336Sdfr * and it exists. 6111558Srgrimes */ 61251968Salfred if (realpath(rpcpath, dirpath) == NULL || 6131558Srgrimes stat(dirpath, &stb) < 0 || 6149336Sdfr (!S_ISDIR(stb.st_mode) && 61574462Salfred (dir_only || !S_ISREG(stb.st_mode))) || 6161558Srgrimes statfs(dirpath, &fsb) < 0) { 6171558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 61831656Sguido syslog(LOG_NOTICE, 61937663Scharnier "mount request from %s for non existent path %s", 62074462Salfred numerichost, dirpath); 6211558Srgrimes if (debug) 62237663Scharnier warnx("stat failed on %s", dirpath); 62328911Sguido bad = ENOENT; /* We will send error reply later */ 6241558Srgrimes } 6251558Srgrimes 6261558Srgrimes /* Check in the exports list */ 6279336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 6281558Srgrimes ep = ex_search(&fsb.f_fsid); 6299336Sdfr hostset = defset = 0; 6309336Sdfr if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 6311558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 63274462Salfred chk_host(dp, saddr, &defset, &hostset)) || 63374462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 63474462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 63528911Sguido if (bad) { 636121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 63728911Sguido (caddr_t)&bad)) 63837663Scharnier syslog(LOG_ERR, "can't send reply"); 63928911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 64028911Sguido return; 64128911Sguido } 6429336Sdfr if (hostset & DP_HOSTSET) 6439336Sdfr fhr.fhr_flag = hostset; 6449336Sdfr else 6459336Sdfr fhr.fhr_flag = defset; 6469336Sdfr fhr.fhr_vers = rqstp->rq_vers; 6471558Srgrimes /* Get the file handle */ 64823681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 6499336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 6501558Srgrimes bad = errno; 65137663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 652121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 6531558Srgrimes (caddr_t)&bad)) 65437663Scharnier syslog(LOG_ERR, "can't send reply"); 6559336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 6561558Srgrimes return; 6571558Srgrimes } 658121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 659121556Speter (caddr_t)&fhr)) 66037663Scharnier syslog(LOG_ERR, "can't send reply"); 66174462Salfred if (!lookup_failed) 66274462Salfred add_mlist(host, dirpath); 6631558Srgrimes else 66474462Salfred add_mlist(numerichost, dirpath); 6651558Srgrimes if (debug) 66637663Scharnier warnx("mount successful"); 667121767Speter if (dolog) 66831656Sguido syslog(LOG_NOTICE, 66931656Sguido "mount request succeeded from %s for %s", 67074462Salfred numerichost, dirpath); 67131656Sguido } else { 6721558Srgrimes bad = EACCES; 67331656Sguido syslog(LOG_NOTICE, 67431656Sguido "mount request denied from %s for %s", 67574462Salfred numerichost, dirpath); 67631656Sguido } 67728911Sguido 678121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 679121556Speter (caddr_t)&bad)) 68037663Scharnier syslog(LOG_ERR, "can't send reply"); 6819336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 6821558Srgrimes return; 6831558Srgrimes case RPCMNT_DUMP: 684121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 68537663Scharnier syslog(LOG_ERR, "can't send reply"); 686121767Speter else if (dolog) 68731656Sguido syslog(LOG_NOTICE, 68831656Sguido "dump request succeeded from %s", 68974462Salfred numerichost); 6901558Srgrimes return; 6911558Srgrimes case RPCMNT_UMOUNT: 6929336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 69331656Sguido syslog(LOG_NOTICE, 69431656Sguido "umount request from %s from unprivileged port", 69574462Salfred numerichost); 6961558Srgrimes svcerr_weakauth(transp); 6971558Srgrimes return; 6981558Srgrimes } 699121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 70031656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 70174462Salfred numerichost); 7021558Srgrimes svcerr_decode(transp); 7031558Srgrimes return; 7041558Srgrimes } 70551968Salfred if (realpath(rpcpath, dirpath) == NULL) { 70651968Salfred syslog(LOG_NOTICE, "umount request from %s " 70751968Salfred "for non existent path %s", 70874462Salfred numerichost, dirpath); 70951968Salfred } 710121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 71137663Scharnier syslog(LOG_ERR, "can't send reply"); 71274462Salfred if (!lookup_failed) 71375635Siedowse del_mlist(host, dirpath); 71475635Siedowse del_mlist(numerichost, dirpath); 715121767Speter if (dolog) 71631656Sguido syslog(LOG_NOTICE, 71731656Sguido "umount request succeeded from %s for %s", 71874462Salfred numerichost, dirpath); 7191558Srgrimes return; 7201558Srgrimes case RPCMNT_UMNTALL: 7219336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 72231656Sguido syslog(LOG_NOTICE, 72331656Sguido "umountall request from %s from unprivileged port", 72474462Salfred numerichost); 7251558Srgrimes svcerr_weakauth(transp); 7261558Srgrimes return; 7271558Srgrimes } 728121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 72937663Scharnier syslog(LOG_ERR, "can't send reply"); 73074462Salfred if (!lookup_failed) 73175635Siedowse del_mlist(host, NULL); 73275635Siedowse del_mlist(numerichost, NULL); 733121767Speter if (dolog) 73431656Sguido syslog(LOG_NOTICE, 73531656Sguido "umountall request succeeded from %s", 73674462Salfred numerichost); 7371558Srgrimes return; 7381558Srgrimes case RPCMNT_EXPORT: 739121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 740121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 741121556Speter (caddr_t)NULL)) 742100117Salfred syslog(LOG_ERR, "can't send reply"); 743121767Speter if (dolog) 74431656Sguido syslog(LOG_NOTICE, 74531656Sguido "export request succeeded from %s", 74674462Salfred numerichost); 7471558Srgrimes return; 7481558Srgrimes default: 7491558Srgrimes svcerr_noproc(transp); 7501558Srgrimes return; 7511558Srgrimes } 7521558Srgrimes} 7531558Srgrimes 7541558Srgrimes/* 7551558Srgrimes * Xdr conversion for a dirpath string 7561558Srgrimes */ 7571558Srgrimesint 7581558Srgrimesxdr_dir(xdrsp, dirp) 7591558Srgrimes XDR *xdrsp; 7601558Srgrimes char *dirp; 7611558Srgrimes{ 7621558Srgrimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 7631558Srgrimes} 7641558Srgrimes 7651558Srgrimes/* 7669336Sdfr * Xdr routine to generate file handle reply 7671558Srgrimes */ 7681558Srgrimesint 7699336Sdfrxdr_fhs(xdrsp, cp) 7701558Srgrimes XDR *xdrsp; 7719336Sdfr caddr_t cp; 7721558Srgrimes{ 77392806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 7749336Sdfr u_long ok = 0, len, auth; 7751558Srgrimes 7761558Srgrimes if (!xdr_long(xdrsp, &ok)) 7771558Srgrimes return (0); 7789336Sdfr switch (fhrp->fhr_vers) { 7799336Sdfr case 1: 7809336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 7819336Sdfr case 3: 7829336Sdfr len = NFSX_V3FH; 7839336Sdfr if (!xdr_long(xdrsp, &len)) 7849336Sdfr return (0); 7859336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 7869336Sdfr return (0); 78783653Speter auth = RPCAUTH_UNIX; 7889336Sdfr len = 1; 7899336Sdfr if (!xdr_long(xdrsp, &len)) 7909336Sdfr return (0); 7919336Sdfr return (xdr_long(xdrsp, &auth)); 7929336Sdfr }; 7939336Sdfr return (0); 7941558Srgrimes} 7951558Srgrimes 7961558Srgrimesint 7971558Srgrimesxdr_mlist(xdrsp, cp) 7981558Srgrimes XDR *xdrsp; 7991558Srgrimes caddr_t cp; 8001558Srgrimes{ 8011558Srgrimes struct mountlist *mlp; 8021558Srgrimes int true = 1; 8031558Srgrimes int false = 0; 8041558Srgrimes char *strp; 8051558Srgrimes 8061558Srgrimes mlp = mlhead; 8071558Srgrimes while (mlp) { 8081558Srgrimes if (!xdr_bool(xdrsp, &true)) 8091558Srgrimes return (0); 8101558Srgrimes strp = &mlp->ml_host[0]; 8111558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 8121558Srgrimes return (0); 8131558Srgrimes strp = &mlp->ml_dirp[0]; 8141558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 8151558Srgrimes return (0); 8161558Srgrimes mlp = mlp->ml_next; 8171558Srgrimes } 8181558Srgrimes if (!xdr_bool(xdrsp, &false)) 8191558Srgrimes return (0); 8201558Srgrimes return (1); 8211558Srgrimes} 8221558Srgrimes 8231558Srgrimes/* 8241558Srgrimes * Xdr conversion for export list 8251558Srgrimes */ 8261558Srgrimesint 827100117Salfredxdr_explist_common(xdrsp, cp, brief) 8281558Srgrimes XDR *xdrsp; 8291558Srgrimes caddr_t cp; 830100117Salfred int brief; 8311558Srgrimes{ 8321558Srgrimes struct exportlist *ep; 8331558Srgrimes int false = 0; 8349336Sdfr int putdef; 8359336Sdfr sigset_t sighup_mask; 8361558Srgrimes 8379336Sdfr sigemptyset(&sighup_mask); 8389336Sdfr sigaddset(&sighup_mask, SIGHUP); 8399336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 8401558Srgrimes ep = exphead; 8411558Srgrimes while (ep) { 8421558Srgrimes putdef = 0; 843100117Salfred if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 844100117Salfred &putdef, brief)) 8451558Srgrimes goto errout; 8461558Srgrimes if (ep->ex_defdir && putdef == 0 && 8471558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 848100117Salfred &putdef, brief)) 8491558Srgrimes goto errout; 8501558Srgrimes ep = ep->ex_next; 8511558Srgrimes } 8529336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8531558Srgrimes if (!xdr_bool(xdrsp, &false)) 8541558Srgrimes return (0); 8551558Srgrimes return (1); 8561558Srgrimeserrout: 8579336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8581558Srgrimes return (0); 8591558Srgrimes} 8601558Srgrimes 8611558Srgrimes/* 8621558Srgrimes * Called from xdr_explist() to traverse the tree and export the 8631558Srgrimes * directory paths. 8641558Srgrimes */ 8651558Srgrimesint 866100117Salfredput_exlist(dp, xdrsp, adp, putdefp, brief) 8671558Srgrimes struct dirlist *dp; 8681558Srgrimes XDR *xdrsp; 8691558Srgrimes struct dirlist *adp; 8701558Srgrimes int *putdefp; 871100117Salfred int brief; 8721558Srgrimes{ 8731558Srgrimes struct grouplist *grp; 8741558Srgrimes struct hostlist *hp; 8751558Srgrimes int true = 1; 8761558Srgrimes int false = 0; 8771558Srgrimes int gotalldir = 0; 8781558Srgrimes char *strp; 8791558Srgrimes 8801558Srgrimes if (dp) { 881100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 8821558Srgrimes return (1); 8831558Srgrimes if (!xdr_bool(xdrsp, &true)) 8841558Srgrimes return (1); 8851558Srgrimes strp = dp->dp_dirp; 8861558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 8871558Srgrimes return (1); 8881558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 8891558Srgrimes gotalldir = 1; 8901558Srgrimes *putdefp = 1; 8911558Srgrimes } 892100117Salfred if (brief) { 893100117Salfred if (!xdr_bool(xdrsp, &true)) 894100117Salfred return (1); 895100117Salfred strp = "(...)"; 896100117Salfred if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 897100117Salfred return (1); 898100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 8991558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 9001558Srgrimes hp = dp->dp_hosts; 9011558Srgrimes while (hp) { 9021558Srgrimes grp = hp->ht_grp; 9031558Srgrimes if (grp->gr_type == GT_HOST) { 9041558Srgrimes if (!xdr_bool(xdrsp, &true)) 9051558Srgrimes return (1); 90674462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 9078871Srgrimes if (!xdr_string(xdrsp, &strp, 9081558Srgrimes RPCMNT_NAMELEN)) 9091558Srgrimes return (1); 9101558Srgrimes } else if (grp->gr_type == GT_NET) { 9111558Srgrimes if (!xdr_bool(xdrsp, &true)) 9121558Srgrimes return (1); 9131558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 9148871Srgrimes if (!xdr_string(xdrsp, &strp, 9151558Srgrimes RPCMNT_NAMELEN)) 9161558Srgrimes return (1); 9171558Srgrimes } 9181558Srgrimes hp = hp->ht_next; 9191558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 9201558Srgrimes hp = adp->dp_hosts; 9211558Srgrimes gotalldir = 0; 9221558Srgrimes } 9231558Srgrimes } 9241558Srgrimes } 9251558Srgrimes if (!xdr_bool(xdrsp, &false)) 9261558Srgrimes return (1); 927100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 9281558Srgrimes return (1); 9291558Srgrimes } 9301558Srgrimes return (0); 9311558Srgrimes} 9321558Srgrimes 933100117Salfredint 934100117Salfredxdr_explist(xdrsp, cp) 935100117Salfred XDR *xdrsp; 936100117Salfred caddr_t cp; 937100117Salfred{ 938100117Salfred 939100117Salfred return xdr_explist_common(xdrsp, cp, 0); 940100117Salfred} 941100117Salfred 942100117Salfredint 943100117Salfredxdr_explist_brief(xdrsp, cp) 944100117Salfred XDR *xdrsp; 945100117Salfred caddr_t cp; 946100117Salfred{ 947100117Salfred 948100117Salfred return xdr_explist_common(xdrsp, cp, 1); 949100117Salfred} 950100117Salfred 95196622Siedowsechar *line; 95296622Siedowseint linesize; 9531558SrgrimesFILE *exp_file; 9541558Srgrimes 9551558Srgrimes/* 956166440Spjd * Get the export list from one, currently open file 9571558Srgrimes */ 958166440Spjdstatic void 959166440Spjdget_exportlist_one() 9601558Srgrimes{ 9611558Srgrimes struct exportlist *ep, *ep2; 9621558Srgrimes struct grouplist *grp, *tgrp; 9631558Srgrimes struct exportlist **epp; 9641558Srgrimes struct dirlist *dirhead; 965166440Spjd struct statfs fsb; 96672650Sgreen struct xucred anon; 9671558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 968166440Spjd int len, has_host, exflags, got_nondir, dirplen, netgrp; 9691558Srgrimes 9701558Srgrimes dirhead = (struct dirlist *)NULL; 9711558Srgrimes while (get_line()) { 9721558Srgrimes if (debug) 97337663Scharnier warnx("got line %s", line); 9741558Srgrimes cp = line; 9751558Srgrimes nextfield(&cp, &endcp); 9761558Srgrimes if (*cp == '#') 9771558Srgrimes goto nextline; 9781558Srgrimes 9791558Srgrimes /* 9801558Srgrimes * Set defaults. 9811558Srgrimes */ 9821558Srgrimes has_host = FALSE; 9831558Srgrimes anon = def_anon; 9841558Srgrimes exflags = MNT_EXPORTED; 9851558Srgrimes got_nondir = 0; 9861558Srgrimes opt_flags = 0; 9871558Srgrimes ep = (struct exportlist *)NULL; 9881558Srgrimes 9891558Srgrimes /* 9901558Srgrimes * Create new exports list entry 9911558Srgrimes */ 9921558Srgrimes len = endcp-cp; 9931558Srgrimes tgrp = grp = get_grp(); 9941558Srgrimes while (len > 0) { 9951558Srgrimes if (len > RPCMNT_NAMELEN) { 9961558Srgrimes getexp_err(ep, tgrp); 9971558Srgrimes goto nextline; 9981558Srgrimes } 9991558Srgrimes if (*cp == '-') { 10001558Srgrimes if (ep == (struct exportlist *)NULL) { 10011558Srgrimes getexp_err(ep, tgrp); 10021558Srgrimes goto nextline; 10031558Srgrimes } 10041558Srgrimes if (debug) 100537663Scharnier warnx("doing opt %s", cp); 10061558Srgrimes got_nondir = 1; 10071558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 10081558Srgrimes &exflags, &anon)) { 10091558Srgrimes getexp_err(ep, tgrp); 10101558Srgrimes goto nextline; 10111558Srgrimes } 10121558Srgrimes } else if (*cp == '/') { 10131558Srgrimes savedc = *endcp; 10141558Srgrimes *endcp = '\0'; 10151558Srgrimes if (check_dirpath(cp) && 10161558Srgrimes statfs(cp, &fsb) >= 0) { 10171558Srgrimes if (got_nondir) { 101837663Scharnier syslog(LOG_ERR, "dirs must be first"); 10191558Srgrimes getexp_err(ep, tgrp); 10201558Srgrimes goto nextline; 10211558Srgrimes } 10221558Srgrimes if (ep) { 10231558Srgrimes if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 10241558Srgrimes ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 10251558Srgrimes getexp_err(ep, tgrp); 10261558Srgrimes goto nextline; 10271558Srgrimes } 10281558Srgrimes } else { 10291558Srgrimes /* 10301558Srgrimes * See if this directory is already 10311558Srgrimes * in the list. 10321558Srgrimes */ 10331558Srgrimes ep = ex_search(&fsb.f_fsid); 10341558Srgrimes if (ep == (struct exportlist *)NULL) { 10351558Srgrimes ep = get_exp(); 10361558Srgrimes ep->ex_fs = fsb.f_fsid; 10371558Srgrimes ep->ex_fsdir = (char *) 10381558Srgrimes malloc(strlen(fsb.f_mntonname) + 1); 10391558Srgrimes if (ep->ex_fsdir) 10401558Srgrimes strcpy(ep->ex_fsdir, 10411558Srgrimes fsb.f_mntonname); 10421558Srgrimes else 10431558Srgrimes out_of_mem(); 10441558Srgrimes if (debug) 104574462Salfred warnx("making new ep fs=0x%x,0x%x", 104674462Salfred fsb.f_fsid.val[0], 104774462Salfred fsb.f_fsid.val[1]); 10481558Srgrimes } else if (debug) 104937663Scharnier warnx("found ep fs=0x%x,0x%x", 10501558Srgrimes fsb.f_fsid.val[0], 10511558Srgrimes fsb.f_fsid.val[1]); 10521558Srgrimes } 10531558Srgrimes 10541558Srgrimes /* 10551558Srgrimes * Add dirpath to export mount point. 10561558Srgrimes */ 10571558Srgrimes dirp = add_expdir(&dirhead, cp, len); 10581558Srgrimes dirplen = len; 10591558Srgrimes } else { 10601558Srgrimes getexp_err(ep, tgrp); 10611558Srgrimes goto nextline; 10621558Srgrimes } 10631558Srgrimes *endcp = savedc; 10641558Srgrimes } else { 10651558Srgrimes savedc = *endcp; 10661558Srgrimes *endcp = '\0'; 10671558Srgrimes got_nondir = 1; 10681558Srgrimes if (ep == (struct exportlist *)NULL) { 10691558Srgrimes getexp_err(ep, tgrp); 10701558Srgrimes goto nextline; 10711558Srgrimes } 10721558Srgrimes 10731558Srgrimes /* 10741558Srgrimes * Get the host or netgroup. 10751558Srgrimes */ 10761558Srgrimes setnetgrent(cp); 10771558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 10781558Srgrimes do { 10791558Srgrimes if (has_host) { 10801558Srgrimes grp->gr_next = get_grp(); 10811558Srgrimes grp = grp->gr_next; 10821558Srgrimes } 10831558Srgrimes if (netgrp) { 108437003Sjoerg if (hst == 0) { 108537663Scharnier syslog(LOG_ERR, 108637663Scharnier "null hostname in netgroup %s, skipping", cp); 108737004Sjoerg grp->gr_type = GT_IGNORE; 108837003Sjoerg } else if (get_host(hst, grp, tgrp)) { 108937663Scharnier syslog(LOG_ERR, 109037663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 109129317Sjlemon grp->gr_type = GT_IGNORE; 10921558Srgrimes } 10937401Swpaul } else if (get_host(cp, grp, tgrp)) { 109437663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 109529317Sjlemon grp->gr_type = GT_IGNORE; 10961558Srgrimes } 10971558Srgrimes has_host = TRUE; 10981558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 10991558Srgrimes endnetgrent(); 11001558Srgrimes *endcp = savedc; 11011558Srgrimes } 11021558Srgrimes cp = endcp; 11031558Srgrimes nextfield(&cp, &endcp); 11041558Srgrimes len = endcp - cp; 11051558Srgrimes } 11061558Srgrimes if (check_options(dirhead)) { 11071558Srgrimes getexp_err(ep, tgrp); 11081558Srgrimes goto nextline; 11091558Srgrimes } 11101558Srgrimes if (!has_host) { 111175641Siedowse grp->gr_type = GT_DEFAULT; 11121558Srgrimes if (debug) 111337663Scharnier warnx("adding a default entry"); 11141558Srgrimes 11151558Srgrimes /* 11161558Srgrimes * Don't allow a network export coincide with a list of 11171558Srgrimes * host(s) on the same line. 11181558Srgrimes */ 11191558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 112075801Siedowse syslog(LOG_ERR, "network/host conflict"); 11211558Srgrimes getexp_err(ep, tgrp); 11221558Srgrimes goto nextline; 112329317Sjlemon 112474462Salfred /* 112574462Salfred * If an export list was specified on this line, make sure 112629317Sjlemon * that we have at least one valid entry, otherwise skip it. 112729317Sjlemon */ 112829317Sjlemon } else { 112929317Sjlemon grp = tgrp; 113074462Salfred while (grp && grp->gr_type == GT_IGNORE) 113129317Sjlemon grp = grp->gr_next; 113229317Sjlemon if (! grp) { 113329317Sjlemon getexp_err(ep, tgrp); 113429317Sjlemon goto nextline; 113529317Sjlemon } 11361558Srgrimes } 11371558Srgrimes 11381558Srgrimes /* 11391558Srgrimes * Loop through hosts, pushing the exports into the kernel. 11401558Srgrimes * After loop, tgrp points to the start of the list and 11411558Srgrimes * grp points to the last entry in the list. 11421558Srgrimes */ 11431558Srgrimes grp = tgrp; 11441558Srgrimes do { 114575635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 114675635Siedowse &fsb)) { 114775635Siedowse getexp_err(ep, tgrp); 114875635Siedowse goto nextline; 114975635Siedowse } 11501558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 11511558Srgrimes 11521558Srgrimes /* 11531558Srgrimes * Success. Update the data structures. 11541558Srgrimes */ 11551558Srgrimes if (has_host) { 11569336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 11571558Srgrimes grp->gr_next = grphead; 11581558Srgrimes grphead = tgrp; 11591558Srgrimes } else { 11601558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 11619336Sdfr opt_flags); 11621558Srgrimes free_grp(grp); 11631558Srgrimes } 11641558Srgrimes dirhead = (struct dirlist *)NULL; 11651558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 11661558Srgrimes ep2 = exphead; 11671558Srgrimes epp = &exphead; 11681558Srgrimes 11691558Srgrimes /* 11701558Srgrimes * Insert in the list in alphabetical order. 11711558Srgrimes */ 11721558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 11731558Srgrimes epp = &ep2->ex_next; 11741558Srgrimes ep2 = ep2->ex_next; 11751558Srgrimes } 11761558Srgrimes if (ep2) 11771558Srgrimes ep->ex_next = ep2; 11781558Srgrimes *epp = ep; 11791558Srgrimes ep->ex_flag |= EX_LINKED; 11801558Srgrimes } 11811558Srgrimesnextline: 11821558Srgrimes if (dirhead) { 11831558Srgrimes free_dir(dirhead); 11841558Srgrimes dirhead = (struct dirlist *)NULL; 11851558Srgrimes } 11861558Srgrimes } 11871558Srgrimes} 11881558Srgrimes 11891558Srgrimes/* 1190166440Spjd * Get the export list from all specified files 1191166440Spjd */ 1192166440Spjdvoid 1193166440Spjdget_exportlist() 1194166440Spjd{ 1195166440Spjd struct exportlist *ep, *ep2; 1196166440Spjd struct grouplist *grp, *tgrp; 1197166440Spjd struct export_args export; 1198166440Spjd struct iovec *iov; 1199166440Spjd struct statfs *fsp, *mntbufp; 1200166440Spjd struct xvfsconf vfc; 1201166440Spjd char *dirp; 1202166440Spjd char errmsg[255]; 1203166440Spjd int dirplen, num, i; 1204166440Spjd int iovlen; 1205168684Spjd int done; 1206166440Spjd 1207166440Spjd bzero(&export, sizeof(export)); 1208166440Spjd export.ex_flags = MNT_DELEXPORT; 1209166440Spjd dirp = NULL; 1210166440Spjd dirplen = 0; 1211166440Spjd iov = NULL; 1212166440Spjd iovlen = 0; 1213166440Spjd bzero(errmsg, sizeof(errmsg)); 1214166440Spjd 1215166440Spjd /* 1216166440Spjd * First, get rid of the old list 1217166440Spjd */ 1218166440Spjd ep = exphead; 1219166440Spjd while (ep) { 1220166440Spjd ep2 = ep; 1221166440Spjd ep = ep->ex_next; 1222166440Spjd free_exp(ep2); 1223166440Spjd } 1224166440Spjd exphead = (struct exportlist *)NULL; 1225166440Spjd 1226166440Spjd grp = grphead; 1227166440Spjd while (grp) { 1228166440Spjd tgrp = grp; 1229166440Spjd grp = grp->gr_next; 1230166440Spjd free_grp(tgrp); 1231166440Spjd } 1232166440Spjd grphead = (struct grouplist *)NULL; 1233166440Spjd 1234166440Spjd /* 1235166440Spjd * And delete exports that are in the kernel for all local 1236166440Spjd * filesystems. 1237166440Spjd * XXX: Should know how to handle all local exportable filesystems. 1238166440Spjd */ 1239166440Spjd num = getmntinfo(&mntbufp, MNT_NOWAIT); 1240166440Spjd 1241166440Spjd if (num > 0) { 1242166440Spjd build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1243166440Spjd build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1244166440Spjd build_iovec(&iov, &iovlen, "from", NULL, 0); 1245166440Spjd build_iovec(&iov, &iovlen, "update", NULL, 0); 1246166440Spjd build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1247166440Spjd build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1248166440Spjd } 1249166440Spjd 1250166440Spjd for (i = 0; i < num; i++) { 1251166440Spjd fsp = &mntbufp[i]; 1252166440Spjd if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1253166440Spjd syslog(LOG_ERR, "getvfsbyname() failed for %s", 1254166440Spjd fsp->f_fstypename); 1255166440Spjd continue; 1256166440Spjd } 1257166440Spjd 1258166440Spjd /* 1259166440Spjd * Do not delete export for network filesystem by 1260166440Spjd * passing "export" arg to nmount(). 1261166440Spjd * It only makes sense to do this for local filesystems. 1262166440Spjd */ 1263166440Spjd if (vfc.vfc_flags & VFCF_NETWORK) 1264166440Spjd continue; 1265166440Spjd 1266166440Spjd iov[1].iov_base = fsp->f_fstypename; 1267166440Spjd iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1268166440Spjd iov[3].iov_base = fsp->f_mntonname; 1269166440Spjd iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1270166440Spjd iov[5].iov_base = fsp->f_mntfromname; 1271166440Spjd iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1272166440Spjd 1273166440Spjd /* 1274166440Spjd * Kick out MNT_ROOTFS. It should not be passed from 1275166440Spjd * userland to kernel. It should only be used 1276166440Spjd * internally in the kernel. 1277166440Spjd */ 1278166440Spjd if (fsp->f_flags & MNT_ROOTFS) { 1279166440Spjd fsp->f_flags &= ~MNT_ROOTFS; 1280166440Spjd } 1281166440Spjd 1282166440Spjd if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1283166440Spjd errno != ENOENT && errno != ENOTSUP) { 1284166440Spjd syslog(LOG_ERR, 1285166440Spjd "can't delete exports for %s: %m %s", 1286166440Spjd fsp->f_mntonname, errmsg); 1287166440Spjd } 1288166440Spjd } 1289166440Spjd 1290166440Spjd if (iov != NULL) { 1291166440Spjd /* Free strings allocated by strdup() in getmntopts.c */ 1292166440Spjd free(iov[0].iov_base); /* fstype */ 1293166440Spjd free(iov[2].iov_base); /* fspath */ 1294166440Spjd free(iov[4].iov_base); /* from */ 1295166440Spjd free(iov[6].iov_base); /* update */ 1296166440Spjd free(iov[8].iov_base); /* export */ 1297166440Spjd free(iov[10].iov_base); /* errmsg */ 1298166440Spjd 1299166440Spjd /* free iov, allocated by realloc() */ 1300166440Spjd free(iov); 1301166440Spjd iovlen = 0; 1302166440Spjd } 1303166440Spjd 1304166440Spjd /* 1305166440Spjd * Read in the exports file and build the list, calling 1306166440Spjd * nmount() as we go along to push the export rules into the kernel. 1307166440Spjd */ 1308168684Spjd done = 0; 1309166440Spjd for (i = 0; exnames[i] != NULL; i++) { 1310166440Spjd if (debug) 1311166440Spjd warnx("reading exports from %s", exnames[i]); 1312166440Spjd if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1313168684Spjd syslog(LOG_WARNING, "can't open %s", exnames[i]); 1314168684Spjd continue; 1315166440Spjd } 1316166440Spjd get_exportlist_one(); 1317166440Spjd fclose(exp_file); 1318168684Spjd done++; 1319166440Spjd } 1320168684Spjd if (done == 0) { 1321168684Spjd syslog(LOG_ERR, "can't open any exports file"); 1322168684Spjd exit(2); 1323168684Spjd } 1324166440Spjd} 1325166440Spjd 1326166440Spjd/* 13271558Srgrimes * Allocate an export list element 13281558Srgrimes */ 13291558Srgrimesstruct exportlist * 13301558Srgrimesget_exp() 13311558Srgrimes{ 13321558Srgrimes struct exportlist *ep; 13331558Srgrimes 13341558Srgrimes ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 13351558Srgrimes if (ep == (struct exportlist *)NULL) 13361558Srgrimes out_of_mem(); 133723681Speter memset(ep, 0, sizeof(struct exportlist)); 13381558Srgrimes return (ep); 13391558Srgrimes} 13401558Srgrimes 13411558Srgrimes/* 13421558Srgrimes * Allocate a group list element 13431558Srgrimes */ 13441558Srgrimesstruct grouplist * 13451558Srgrimesget_grp() 13461558Srgrimes{ 13471558Srgrimes struct grouplist *gp; 13481558Srgrimes 13491558Srgrimes gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 13501558Srgrimes if (gp == (struct grouplist *)NULL) 13511558Srgrimes out_of_mem(); 135223681Speter memset(gp, 0, sizeof(struct grouplist)); 13531558Srgrimes return (gp); 13541558Srgrimes} 13551558Srgrimes 13561558Srgrimes/* 13571558Srgrimes * Clean up upon an error in get_exportlist(). 13581558Srgrimes */ 13591558Srgrimesvoid 13601558Srgrimesgetexp_err(ep, grp) 13611558Srgrimes struct exportlist *ep; 13621558Srgrimes struct grouplist *grp; 13631558Srgrimes{ 13641558Srgrimes struct grouplist *tgrp; 13651558Srgrimes 1366100336Sjoerg if (!(opt_flags & OP_QUIET)) 1367100336Sjoerg syslog(LOG_ERR, "bad exports list line %s", line); 13681558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 13691558Srgrimes free_exp(ep); 13701558Srgrimes while (grp) { 13711558Srgrimes tgrp = grp; 13721558Srgrimes grp = grp->gr_next; 13731558Srgrimes free_grp(tgrp); 13741558Srgrimes } 13751558Srgrimes} 13761558Srgrimes 13771558Srgrimes/* 13781558Srgrimes * Search the export list for a matching fs. 13791558Srgrimes */ 13801558Srgrimesstruct exportlist * 13811558Srgrimesex_search(fsid) 13821558Srgrimes fsid_t *fsid; 13831558Srgrimes{ 13841558Srgrimes struct exportlist *ep; 13851558Srgrimes 13861558Srgrimes ep = exphead; 13871558Srgrimes while (ep) { 13881558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 13891558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 13901558Srgrimes return (ep); 13911558Srgrimes ep = ep->ex_next; 13921558Srgrimes } 13931558Srgrimes return (ep); 13941558Srgrimes} 13951558Srgrimes 13961558Srgrimes/* 13971558Srgrimes * Add a directory path to the list. 13981558Srgrimes */ 13991558Srgrimeschar * 14001558Srgrimesadd_expdir(dpp, cp, len) 14011558Srgrimes struct dirlist **dpp; 14021558Srgrimes char *cp; 14031558Srgrimes int len; 14041558Srgrimes{ 14051558Srgrimes struct dirlist *dp; 14061558Srgrimes 14071558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 140837663Scharnier if (dp == (struct dirlist *)NULL) 140937663Scharnier out_of_mem(); 14101558Srgrimes dp->dp_left = *dpp; 14111558Srgrimes dp->dp_right = (struct dirlist *)NULL; 14121558Srgrimes dp->dp_flag = 0; 14131558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 14141558Srgrimes strcpy(dp->dp_dirp, cp); 14151558Srgrimes *dpp = dp; 14161558Srgrimes return (dp->dp_dirp); 14171558Srgrimes} 14181558Srgrimes 14191558Srgrimes/* 14201558Srgrimes * Hang the dir list element off the dirpath binary tree as required 14211558Srgrimes * and update the entry for host. 14221558Srgrimes */ 14231558Srgrimesvoid 14249336Sdfrhang_dirp(dp, grp, ep, flags) 14251558Srgrimes struct dirlist *dp; 14261558Srgrimes struct grouplist *grp; 14271558Srgrimes struct exportlist *ep; 14289336Sdfr int flags; 14291558Srgrimes{ 14301558Srgrimes struct hostlist *hp; 14311558Srgrimes struct dirlist *dp2; 14321558Srgrimes 14339336Sdfr if (flags & OP_ALLDIRS) { 14341558Srgrimes if (ep->ex_defdir) 14351558Srgrimes free((caddr_t)dp); 14361558Srgrimes else 14371558Srgrimes ep->ex_defdir = dp; 14389336Sdfr if (grp == (struct grouplist *)NULL) { 14391558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 14409336Sdfr } else while (grp) { 14411558Srgrimes hp = get_ht(); 14421558Srgrimes hp->ht_grp = grp; 14431558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 14441558Srgrimes ep->ex_defdir->dp_hosts = hp; 14451558Srgrimes grp = grp->gr_next; 14461558Srgrimes } 14471558Srgrimes } else { 14481558Srgrimes 14491558Srgrimes /* 145037663Scharnier * Loop through the directories adding them to the tree. 14511558Srgrimes */ 14521558Srgrimes while (dp) { 14531558Srgrimes dp2 = dp->dp_left; 14549336Sdfr add_dlist(&ep->ex_dirl, dp, grp, flags); 14551558Srgrimes dp = dp2; 14561558Srgrimes } 14571558Srgrimes } 14581558Srgrimes} 14591558Srgrimes 14601558Srgrimes/* 14611558Srgrimes * Traverse the binary tree either updating a node that is already there 14621558Srgrimes * for the new directory or adding the new node. 14631558Srgrimes */ 14641558Srgrimesvoid 14659336Sdfradd_dlist(dpp, newdp, grp, flags) 14661558Srgrimes struct dirlist **dpp; 14671558Srgrimes struct dirlist *newdp; 14681558Srgrimes struct grouplist *grp; 14699336Sdfr int flags; 14701558Srgrimes{ 14711558Srgrimes struct dirlist *dp; 14721558Srgrimes struct hostlist *hp; 14731558Srgrimes int cmp; 14741558Srgrimes 14751558Srgrimes dp = *dpp; 14761558Srgrimes if (dp) { 14771558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 14781558Srgrimes if (cmp > 0) { 14799336Sdfr add_dlist(&dp->dp_left, newdp, grp, flags); 14801558Srgrimes return; 14811558Srgrimes } else if (cmp < 0) { 14829336Sdfr add_dlist(&dp->dp_right, newdp, grp, flags); 14831558Srgrimes return; 14841558Srgrimes } else 14851558Srgrimes free((caddr_t)newdp); 14861558Srgrimes } else { 14871558Srgrimes dp = newdp; 14881558Srgrimes dp->dp_left = (struct dirlist *)NULL; 14891558Srgrimes *dpp = dp; 14901558Srgrimes } 14911558Srgrimes if (grp) { 14921558Srgrimes 14931558Srgrimes /* 14941558Srgrimes * Hang all of the host(s) off of the directory point. 14951558Srgrimes */ 14961558Srgrimes do { 14971558Srgrimes hp = get_ht(); 14981558Srgrimes hp->ht_grp = grp; 14991558Srgrimes hp->ht_next = dp->dp_hosts; 15001558Srgrimes dp->dp_hosts = hp; 15011558Srgrimes grp = grp->gr_next; 15021558Srgrimes } while (grp); 15039336Sdfr } else { 15041558Srgrimes dp->dp_flag |= DP_DEFSET; 15059336Sdfr } 15061558Srgrimes} 15071558Srgrimes 15081558Srgrimes/* 15091558Srgrimes * Search for a dirpath on the export point. 15101558Srgrimes */ 15111558Srgrimesstruct dirlist * 151274462Salfreddirp_search(dp, dirp) 15131558Srgrimes struct dirlist *dp; 151474462Salfred char *dirp; 15151558Srgrimes{ 15161558Srgrimes int cmp; 15171558Srgrimes 15181558Srgrimes if (dp) { 151974462Salfred cmp = strcmp(dp->dp_dirp, dirp); 15201558Srgrimes if (cmp > 0) 152174462Salfred return (dirp_search(dp->dp_left, dirp)); 15221558Srgrimes else if (cmp < 0) 152374462Salfred return (dirp_search(dp->dp_right, dirp)); 15241558Srgrimes else 15251558Srgrimes return (dp); 15261558Srgrimes } 15271558Srgrimes return (dp); 15281558Srgrimes} 15291558Srgrimes 15301558Srgrimes/* 15311558Srgrimes * Scan for a host match in a directory tree. 15321558Srgrimes */ 15331558Srgrimesint 15349336Sdfrchk_host(dp, saddr, defsetp, hostsetp) 15351558Srgrimes struct dirlist *dp; 153674462Salfred struct sockaddr *saddr; 15371558Srgrimes int *defsetp; 15389336Sdfr int *hostsetp; 15391558Srgrimes{ 15401558Srgrimes struct hostlist *hp; 15411558Srgrimes struct grouplist *grp; 154274462Salfred struct addrinfo *ai; 15431558Srgrimes 15441558Srgrimes if (dp) { 15451558Srgrimes if (dp->dp_flag & DP_DEFSET) 15469336Sdfr *defsetp = dp->dp_flag; 15471558Srgrimes hp = dp->dp_hosts; 15481558Srgrimes while (hp) { 15491558Srgrimes grp = hp->ht_grp; 15501558Srgrimes switch (grp->gr_type) { 15511558Srgrimes case GT_HOST: 155274462Salfred ai = grp->gr_ptr.gt_addrinfo; 155374462Salfred for (; ai; ai = ai->ai_next) { 155475801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 155574462Salfred *hostsetp = 155674462Salfred (hp->ht_flag | DP_HOSTSET); 155774462Salfred return (1); 155874462Salfred } 15599336Sdfr } 156075801Siedowse break; 15611558Srgrimes case GT_NET: 156275801Siedowse if (!sacmp(saddr, (struct sockaddr *) 156375801Siedowse &grp->gr_ptr.gt_net.nt_net, 156475801Siedowse (struct sockaddr *) 156575801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 156674462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 156774462Salfred return (1); 156874462Salfred } 156975801Siedowse break; 157075801Siedowse } 15711558Srgrimes hp = hp->ht_next; 15721558Srgrimes } 15731558Srgrimes } 15741558Srgrimes return (0); 15751558Srgrimes} 15761558Srgrimes 15771558Srgrimes/* 15781558Srgrimes * Scan tree for a host that matches the address. 15791558Srgrimes */ 15801558Srgrimesint 15811558Srgrimesscan_tree(dp, saddr) 15821558Srgrimes struct dirlist *dp; 158374462Salfred struct sockaddr *saddr; 15841558Srgrimes{ 15859336Sdfr int defset, hostset; 15861558Srgrimes 15871558Srgrimes if (dp) { 15881558Srgrimes if (scan_tree(dp->dp_left, saddr)) 15891558Srgrimes return (1); 15909336Sdfr if (chk_host(dp, saddr, &defset, &hostset)) 15911558Srgrimes return (1); 15921558Srgrimes if (scan_tree(dp->dp_right, saddr)) 15931558Srgrimes return (1); 15941558Srgrimes } 15951558Srgrimes return (0); 15961558Srgrimes} 15971558Srgrimes 15981558Srgrimes/* 15991558Srgrimes * Traverse the dirlist tree and free it up. 16001558Srgrimes */ 16011558Srgrimesvoid 16021558Srgrimesfree_dir(dp) 16031558Srgrimes struct dirlist *dp; 16041558Srgrimes{ 16051558Srgrimes 16061558Srgrimes if (dp) { 16071558Srgrimes free_dir(dp->dp_left); 16081558Srgrimes free_dir(dp->dp_right); 16091558Srgrimes free_host(dp->dp_hosts); 16101558Srgrimes free((caddr_t)dp); 16111558Srgrimes } 16121558Srgrimes} 16131558Srgrimes 16141558Srgrimes/* 16151558Srgrimes * Parse the option string and update fields. 16161558Srgrimes * Option arguments may either be -<option>=<value> or 16171558Srgrimes * -<option> <value> 16181558Srgrimes */ 16191558Srgrimesint 16201558Srgrimesdo_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 16211558Srgrimes char **cpp, **endcpp; 16221558Srgrimes struct exportlist *ep; 16231558Srgrimes struct grouplist *grp; 16241558Srgrimes int *has_hostp; 16251558Srgrimes int *exflagsp; 162672650Sgreen struct xucred *cr; 16271558Srgrimes{ 16281558Srgrimes char *cpoptarg, *cpoptend; 16291558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 16301558Srgrimes int allflag, usedarg; 16311558Srgrimes 163251968Salfred savedc2 = '\0'; 16331558Srgrimes cpopt = *cpp; 16341558Srgrimes cpopt++; 16351558Srgrimes cp = *endcpp; 16361558Srgrimes savedc = *cp; 16371558Srgrimes *cp = '\0'; 16381558Srgrimes while (cpopt && *cpopt) { 16391558Srgrimes allflag = 1; 16401558Srgrimes usedarg = -2; 164137663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 16421558Srgrimes *cpoptend++ = '\0'; 164337663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 16441558Srgrimes *cpoptarg++ = '\0'; 16451558Srgrimes } else { 164637663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 16471558Srgrimes *cpoptarg++ = '\0'; 16481558Srgrimes else { 16491558Srgrimes *cp = savedc; 16501558Srgrimes nextfield(&cp, &endcp); 16511558Srgrimes **endcpp = '\0'; 16521558Srgrimes if (endcp > cp && *cp != '-') { 16531558Srgrimes cpoptarg = cp; 16541558Srgrimes savedc2 = *endcp; 16551558Srgrimes *endcp = '\0'; 16561558Srgrimes usedarg = 0; 16571558Srgrimes } 16581558Srgrimes } 16591558Srgrimes } 16601558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 16611558Srgrimes *exflagsp |= MNT_EXRDONLY; 16621558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 16631558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 16641558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 16651558Srgrimes usedarg++; 16661558Srgrimes parsecred(cpoptarg, cr); 16671558Srgrimes if (allflag == 0) { 16681558Srgrimes *exflagsp |= MNT_EXPORTANON; 16691558Srgrimes opt_flags |= OP_MAPALL; 16701558Srgrimes } else 16711558Srgrimes opt_flags |= OP_MAPROOT; 16721558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 167375801Siedowse !strcmp(cpopt, "m"))) { 16741558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 167537663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 16761558Srgrimes return (1); 16771558Srgrimes } 16781558Srgrimes usedarg++; 16791558Srgrimes opt_flags |= OP_MASK; 16801558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 16811558Srgrimes !strcmp(cpopt, "n"))) { 168274462Salfred if (strchr(cpoptarg, '/') != NULL) { 168374462Salfred if (debug) 168474462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 168574462Salfred opt_flags |= OP_MASKLEN; 168674462Salfred } 16871558Srgrimes if (grp->gr_type != GT_NULL) { 168837663Scharnier syslog(LOG_ERR, "network/host conflict"); 16891558Srgrimes return (1); 16901558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 169137663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 16921558Srgrimes return (1); 16931558Srgrimes } 16941558Srgrimes grp->gr_type = GT_NET; 16951558Srgrimes *has_hostp = 1; 16961558Srgrimes usedarg++; 16971558Srgrimes opt_flags |= OP_NET; 16981558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 16991558Srgrimes opt_flags |= OP_ALLDIRS; 170027447Sdfr } else if (!strcmp(cpopt, "public")) { 170127447Sdfr *exflagsp |= MNT_EXPUBLIC; 170227447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 170327447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 170427447Sdfr opt_flags |= OP_MAPALL; 170527447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 170627447Sdfr ep->ex_indexfile = strdup(cpoptarg); 1707100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 1708100336Sjoerg opt_flags |= OP_QUIET; 17091558Srgrimes } else { 171037663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 17111558Srgrimes return (1); 17121558Srgrimes } 17131558Srgrimes if (usedarg >= 0) { 17141558Srgrimes *endcp = savedc2; 17151558Srgrimes **endcpp = savedc; 17161558Srgrimes if (usedarg > 0) { 17171558Srgrimes *cpp = cp; 17181558Srgrimes *endcpp = endcp; 17191558Srgrimes } 17201558Srgrimes return (0); 17211558Srgrimes } 17221558Srgrimes cpopt = cpoptend; 17231558Srgrimes } 17241558Srgrimes **endcpp = savedc; 17251558Srgrimes return (0); 17261558Srgrimes} 17271558Srgrimes 17281558Srgrimes/* 17291558Srgrimes * Translate a character string to the corresponding list of network 17301558Srgrimes * addresses for a hostname. 17311558Srgrimes */ 17321558Srgrimesint 17337401Swpaulget_host(cp, grp, tgrp) 17341558Srgrimes char *cp; 17351558Srgrimes struct grouplist *grp; 17367401Swpaul struct grouplist *tgrp; 17371558Srgrimes{ 17387401Swpaul struct grouplist *checkgrp; 173975635Siedowse struct addrinfo *ai, *tai, hints; 174074462Salfred int ecode; 174174462Salfred char host[NI_MAXHOST]; 17421558Srgrimes 174374462Salfred if (grp->gr_type != GT_NULL) { 174474462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 17451558Srgrimes return (1); 17461558Srgrimes } 174774462Salfred memset(&hints, 0, sizeof hints); 174874462Salfred hints.ai_flags = AI_CANONNAME; 174974462Salfred hints.ai_protocol = IPPROTO_UDP; 175074462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 175174462Salfred if (ecode != 0) { 175275635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 175374462Salfred return 1; 175474462Salfred } 175574462Salfred grp->gr_ptr.gt_addrinfo = ai; 175674462Salfred while (ai != NULL) { 175774462Salfred if (ai->ai_canonname == NULL) { 175874462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 1759146187Sume sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 176074462Salfred strlcpy(host, "?", sizeof(host)); 176174462Salfred ai->ai_canonname = strdup(host); 176274462Salfred ai->ai_flags |= AI_CANONNAME; 176375641Siedowse } 176474462Salfred if (debug) 176575635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 176675635Siedowse /* 176775635Siedowse * Sanity check: make sure we don't already have an entry 176875635Siedowse * for this host in the grouplist. 176975635Siedowse */ 177075635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 177175635Siedowse checkgrp = checkgrp->gr_next) { 177275635Siedowse if (checkgrp->gr_type != GT_HOST) 177375635Siedowse continue; 177475635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 177575635Siedowse tai = tai->ai_next) { 177675801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 177775635Siedowse continue; 177875635Siedowse if (debug) 177975635Siedowse fprintf(stderr, 178075635Siedowse "ignoring duplicate host %s\n", 178175635Siedowse ai->ai_canonname); 178275635Siedowse grp->gr_type = GT_IGNORE; 178375635Siedowse return (0); 178475635Siedowse } 178575635Siedowse } 178674462Salfred ai = ai->ai_next; 17871558Srgrimes } 178875635Siedowse grp->gr_type = GT_HOST; 17891558Srgrimes return (0); 17901558Srgrimes} 17911558Srgrimes 17921558Srgrimes/* 17931558Srgrimes * Free up an exports list component 17941558Srgrimes */ 17951558Srgrimesvoid 17961558Srgrimesfree_exp(ep) 17971558Srgrimes struct exportlist *ep; 17981558Srgrimes{ 17991558Srgrimes 18001558Srgrimes if (ep->ex_defdir) { 18011558Srgrimes free_host(ep->ex_defdir->dp_hosts); 18021558Srgrimes free((caddr_t)ep->ex_defdir); 18031558Srgrimes } 18041558Srgrimes if (ep->ex_fsdir) 18051558Srgrimes free(ep->ex_fsdir); 180627447Sdfr if (ep->ex_indexfile) 180727447Sdfr free(ep->ex_indexfile); 18081558Srgrimes free_dir(ep->ex_dirl); 18091558Srgrimes free((caddr_t)ep); 18101558Srgrimes} 18111558Srgrimes 18121558Srgrimes/* 18131558Srgrimes * Free hosts. 18141558Srgrimes */ 18151558Srgrimesvoid 18161558Srgrimesfree_host(hp) 18171558Srgrimes struct hostlist *hp; 18181558Srgrimes{ 18191558Srgrimes struct hostlist *hp2; 18201558Srgrimes 18211558Srgrimes while (hp) { 18221558Srgrimes hp2 = hp; 18231558Srgrimes hp = hp->ht_next; 18241558Srgrimes free((caddr_t)hp2); 18251558Srgrimes } 18261558Srgrimes} 18271558Srgrimes 18281558Srgrimesstruct hostlist * 18291558Srgrimesget_ht() 18301558Srgrimes{ 18311558Srgrimes struct hostlist *hp; 18321558Srgrimes 18331558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 18341558Srgrimes if (hp == (struct hostlist *)NULL) 18351558Srgrimes out_of_mem(); 18361558Srgrimes hp->ht_next = (struct hostlist *)NULL; 18379336Sdfr hp->ht_flag = 0; 18381558Srgrimes return (hp); 18391558Srgrimes} 18401558Srgrimes 18411558Srgrimes/* 18421558Srgrimes * Out of memory, fatal 18431558Srgrimes */ 18441558Srgrimesvoid 18451558Srgrimesout_of_mem() 18461558Srgrimes{ 18471558Srgrimes 184837663Scharnier syslog(LOG_ERR, "out of memory"); 18491558Srgrimes exit(2); 18501558Srgrimes} 18511558Srgrimes 18521558Srgrimes/* 1853158857Srodrigc * Do the nmount() syscall with the update flag to push the export info into 18541558Srgrimes * the kernel. 18551558Srgrimes */ 18561558Srgrimesint 1857158857Srodrigcdo_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 1858158857Srodrigc struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 18591558Srgrimes{ 186075841Siedowse struct statfs fsb1; 186174462Salfred struct addrinfo *ai; 1862158857Srodrigc struct export_args eap; 1863158857Srodrigc char errmsg[255]; 1864158857Srodrigc char *cp; 18651558Srgrimes int done; 1866158857Srodrigc char savedc; 1867158857Srodrigc struct iovec *iov; 1868158857Srodrigc int iovlen; 1869158857Srodrigc int ret; 18701558Srgrimes 1871158857Srodrigc cp = NULL; 1872158857Srodrigc savedc = '\0'; 1873158857Srodrigc iov = NULL; 1874158857Srodrigc iovlen = 0; 1875158857Srodrigc ret = 0; 187675801Siedowse 1877158857Srodrigc bzero(&eap, sizeof(eap)); 1878158857Srodrigc bzero(errmsg, sizeof(errmsg)); 1879158857Srodrigc eap.ex_flags = exflags; 1880158857Srodrigc eap.ex_anon = *anoncrp; 1881158857Srodrigc eap.ex_indexfile = ep->ex_indexfile; 188275641Siedowse if (grp->gr_type == GT_HOST) 188374462Salfred ai = grp->gr_ptr.gt_addrinfo; 188475641Siedowse else 188575641Siedowse ai = NULL; 18861558Srgrimes done = FALSE; 1887158857Srodrigc 1888158857Srodrigc build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1889158857Srodrigc build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1890158857Srodrigc build_iovec(&iov, &iovlen, "from", NULL, 0); 1891158857Srodrigc build_iovec(&iov, &iovlen, "update", NULL, 0); 1892158857Srodrigc build_iovec(&iov, &iovlen, "export", &eap, sizeof(eap)); 1893158857Srodrigc build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1894158857Srodrigc 18951558Srgrimes while (!done) { 18961558Srgrimes switch (grp->gr_type) { 18971558Srgrimes case GT_HOST: 189875641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 189974462Salfred goto skip; 1900158857Srodrigc eap.ex_addr = ai->ai_addr; 1901158857Srodrigc eap.ex_addrlen = ai->ai_addrlen; 1902158857Srodrigc eap.ex_masklen = 0; 19031558Srgrimes break; 19041558Srgrimes case GT_NET: 190575801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 190674462Salfred have_v6 == 0) 190774462Salfred goto skip; 1908158857Srodrigc eap.ex_addr = 190975801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 1910158857Srodrigc eap.ex_addrlen = 1911158857Srodrigc ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 1912158857Srodrigc eap.ex_mask = 191375801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 1914158857Srodrigc eap.ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 19151558Srgrimes break; 191675641Siedowse case GT_DEFAULT: 1917158857Srodrigc eap.ex_addr = NULL; 1918158857Srodrigc eap.ex_addrlen = 0; 1919158857Srodrigc eap.ex_mask = NULL; 1920158857Srodrigc eap.ex_masklen = 0; 192175641Siedowse break; 19227401Swpaul case GT_IGNORE: 1923158857Srodrigc ret = 0; 1924158857Srodrigc goto error_exit; 19257401Swpaul break; 19261558Srgrimes default: 192737663Scharnier syslog(LOG_ERR, "bad grouptype"); 19281558Srgrimes if (cp) 19291558Srgrimes *cp = savedc; 1930158857Srodrigc ret = 1; 1931158857Srodrigc goto error_exit; 19321558Srgrimes }; 19331558Srgrimes 19341558Srgrimes /* 19351558Srgrimes * XXX: 19361558Srgrimes * Maybe I should just use the fsb->f_mntonname path instead 19371558Srgrimes * of looping back up the dirp to the mount point?? 19381558Srgrimes * Also, needs to know how to export all types of local 193996707Strhodes * exportable filesystems and not just "ufs". 19401558Srgrimes */ 1941158857Srodrigc iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 1942158857Srodrigc iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 1943158857Srodrigc iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 1944158857Srodrigc iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 1945158857Srodrigc iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 1946158857Srodrigc iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 1947158857Srodrigc 1948163512Srink /* 1949163512Srink * Remount the filesystem, but chop off the MNT_ROOTFS flag 1950163512Srink * as it is used internally (and will result in an error if 1951163512Srink * specified) 1952163512Srink */ 1953163512Srink while (nmount(iov, iovlen, fsb->f_flags & ~MNT_ROOTFS) < 0) { 19541558Srgrimes if (cp) 19551558Srgrimes *cp-- = savedc; 19561558Srgrimes else 19571558Srgrimes cp = dirp + dirplen - 1; 1958158857Srodrigc if (opt_flags & OP_QUIET) { 1959158857Srodrigc ret = 1; 1960158857Srodrigc goto error_exit; 1961158857Srodrigc } 19621558Srgrimes if (errno == EPERM) { 196375635Siedowse if (debug) 196475635Siedowse warnx("can't change attributes for %s", 196575635Siedowse dirp); 19661558Srgrimes syslog(LOG_ERR, 196737663Scharnier "can't change attributes for %s", dirp); 1968158857Srodrigc ret = 1; 1969158857Srodrigc goto error_exit; 19701558Srgrimes } 19711558Srgrimes if (opt_flags & OP_ALLDIRS) { 1972100336Sjoerg if (errno == EINVAL) 1973100336Sjoerg syslog(LOG_ERR, 1974100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 1975100336Sjoerg dirp); 1976100336Sjoerg else 1977100336Sjoerg syslog(LOG_ERR, 1978100336Sjoerg "could not remount %s: %m", 1979100336Sjoerg dirp); 1980158857Srodrigc ret = 1; 1981158857Srodrigc goto error_exit; 19821558Srgrimes } 19831558Srgrimes /* back up over the last component */ 19841558Srgrimes while (*cp == '/' && cp > dirp) 19851558Srgrimes cp--; 19861558Srgrimes while (*(cp - 1) != '/' && cp > dirp) 19871558Srgrimes cp--; 19881558Srgrimes if (cp == dirp) { 19891558Srgrimes if (debug) 199037663Scharnier warnx("mnt unsucc"); 1991166258Srodrigc syslog(LOG_ERR, "can't export %s %s", dirp, 1992166258Srodrigc errmsg); 1993158857Srodrigc ret = 1; 1994158857Srodrigc goto error_exit; 19951558Srgrimes } 19961558Srgrimes savedc = *cp; 19971558Srgrimes *cp = '\0'; 199875841Siedowse /* Check that we're still on the same filesystem. */ 199975841Siedowse if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid, 200075841Siedowse &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) { 200175841Siedowse *cp = savedc; 2002166258Srodrigc syslog(LOG_ERR, "can't export %s %s", dirp, 2003166258Srodrigc errmsg); 2004158857Srodrigc ret = 1; 2005158857Srodrigc goto error_exit; 200675841Siedowse } 20071558Srgrimes } 200874462Salfredskip: 200975641Siedowse if (ai != NULL) 201074462Salfred ai = ai->ai_next; 201175641Siedowse if (ai == NULL) 20121558Srgrimes done = TRUE; 20131558Srgrimes } 20141558Srgrimes if (cp) 20151558Srgrimes *cp = savedc; 2016158857Srodrigcerror_exit: 2017158857Srodrigc /* free strings allocated by strdup() in getmntopts.c */ 2018158857Srodrigc if (iov != NULL) { 2019158857Srodrigc free(iov[0].iov_base); /* fstype */ 2020158857Srodrigc free(iov[2].iov_base); /* fspath */ 2021158857Srodrigc free(iov[4].iov_base); /* from */ 2022158857Srodrigc free(iov[6].iov_base); /* update */ 2023158857Srodrigc free(iov[8].iov_base); /* export */ 2024158857Srodrigc free(iov[10].iov_base); /* errmsg */ 2025158857Srodrigc 2026158857Srodrigc /* free iov, allocated by realloc() */ 2027158857Srodrigc free(iov); 2028158857Srodrigc } 2029158857Srodrigc return (ret); 20301558Srgrimes} 20311558Srgrimes 20321558Srgrimes/* 20331558Srgrimes * Translate a net address. 203475801Siedowse * 203575801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 20361558Srgrimes */ 20371558Srgrimesint 20381558Srgrimesget_net(cp, net, maskflg) 20391558Srgrimes char *cp; 20401558Srgrimes struct netmsk *net; 20411558Srgrimes int maskflg; 20421558Srgrimes{ 204375861Siedowse struct netent *np = NULL; 204474462Salfred char *name, *p, *prefp; 204575801Siedowse struct sockaddr_in sin; 204675861Siedowse struct sockaddr *sa = NULL; 204774462Salfred struct addrinfo hints, *ai = NULL; 204874462Salfred char netname[NI_MAXHOST]; 204974462Salfred long preflen; 20501558Srgrimes 205175635Siedowse p = prefp = NULL; 205274462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 205374462Salfred p = strchr(cp, '/'); 205474462Salfred *p = '\0'; 205574462Salfred prefp = p + 1; 205674462Salfred } 205774462Salfred 205875861Siedowse /* 205975861Siedowse * Check for a numeric address first. We wish to avoid 206075861Siedowse * possible DNS lookups in getnetbyname(). 206175861Siedowse */ 206275861Siedowse if (isxdigit(*cp) || *cp == ':') { 206374462Salfred memset(&hints, 0, sizeof hints); 206475801Siedowse /* Ensure the mask and the network have the same family. */ 206575801Siedowse if (maskflg && (opt_flags & OP_NET)) 206675801Siedowse hints.ai_family = net->nt_net.ss_family; 206775801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 206875801Siedowse hints.ai_family = net->nt_mask.ss_family; 206975801Siedowse else 207075801Siedowse hints.ai_family = AF_UNSPEC; 207174462Salfred hints.ai_flags = AI_NUMERICHOST; 207275861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 207375861Siedowse sa = ai->ai_addr; 207475861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 207574462Salfred /* 207675801Siedowse * The address in `cp' is really a network address, so 207775801Siedowse * use inet_network() to re-interpret this correctly. 207875801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 207974462Salfred */ 208075801Siedowse bzero(&sin, sizeof sin); 208174462Salfred sin.sin_family = AF_INET; 208274462Salfred sin.sin_len = sizeof sin; 208375801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 208474462Salfred if (debug) 208575801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 208675801Siedowse inet_ntoa(sin.sin_addr)); 208774462Salfred sa = (struct sockaddr *)&sin; 208875861Siedowse } 208975861Siedowse } 209075861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 209175861Siedowse bzero(&sin, sizeof sin); 209275861Siedowse sin.sin_family = AF_INET; 209375861Siedowse sin.sin_len = sizeof sin; 209475861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 209575861Siedowse sa = (struct sockaddr *)&sin; 209675861Siedowse } 209775861Siedowse if (sa == NULL) 209874462Salfred goto fail; 209925318Spst 210075801Siedowse if (maskflg) { 210175801Siedowse /* The specified sockaddr is a mask. */ 210275801Siedowse if (checkmask(sa) != 0) 210375801Siedowse goto fail; 210475801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 210575801Siedowse opt_flags |= OP_HAVEMASK; 210675801Siedowse } else { 210775801Siedowse /* The specified sockaddr is a network address. */ 210875801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 210974462Salfred 211075801Siedowse /* Get a network name for the export list. */ 211175801Siedowse if (np) { 211275801Siedowse name = np->n_name; 211375801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2114146187Sume NULL, 0, NI_NUMERICHOST) == 0) { 211575801Siedowse name = netname; 211675801Siedowse } else { 211775801Siedowse goto fail; 211875801Siedowse } 211975801Siedowse if ((net->nt_name = strdup(name)) == NULL) 212075801Siedowse out_of_mem(); 212175801Siedowse 212275801Siedowse /* 212375801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 212475801Siedowse * from the class of an IPv4 address. 212575801Siedowse */ 212674462Salfred if (opt_flags & OP_MASKLEN) { 212774462Salfred preflen = strtol(prefp, NULL, 10); 212875801Siedowse if (preflen < 0L || preflen == LONG_MAX) 212974462Salfred goto fail; 213075801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 213175801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 213275801Siedowse goto fail; 213375801Siedowse opt_flags |= OP_HAVEMASK; 213474462Salfred *p = '/'; 213575801Siedowse } else if (sa->sa_family == AF_INET && 213675801Siedowse (opt_flags & OP_MASK) == 0) { 213775801Siedowse in_addr_t addr; 213874462Salfred 213975801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 214075801Siedowse if (IN_CLASSA(addr)) 214175801Siedowse preflen = 8; 214275801Siedowse else if (IN_CLASSB(addr)) 214375801Siedowse preflen = 16; 214475801Siedowse else if (IN_CLASSC(addr)) 214575801Siedowse preflen = 24; 214675801Siedowse else if (IN_CLASSD(addr)) 214775801Siedowse preflen = 28; 214875801Siedowse else 214975801Siedowse preflen = 32; /* XXX */ 215075801Siedowse 215175801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 215275801Siedowse makemask(&net->nt_mask, (int)preflen); 215375801Siedowse opt_flags |= OP_HAVEMASK; 215474462Salfred } 215574462Salfred } 215674462Salfred 215774462Salfred if (ai) 215874462Salfred freeaddrinfo(ai); 215974462Salfred return 0; 216074462Salfred 216174462Salfredfail: 216274462Salfred if (ai) 216374462Salfred freeaddrinfo(ai); 216474462Salfred return 1; 21651558Srgrimes} 21661558Srgrimes 21671558Srgrimes/* 21681558Srgrimes * Parse out the next white space separated field 21691558Srgrimes */ 21701558Srgrimesvoid 21711558Srgrimesnextfield(cp, endcp) 21721558Srgrimes char **cp; 21731558Srgrimes char **endcp; 21741558Srgrimes{ 21751558Srgrimes char *p; 21761558Srgrimes 21771558Srgrimes p = *cp; 21781558Srgrimes while (*p == ' ' || *p == '\t') 21791558Srgrimes p++; 21801558Srgrimes if (*p == '\n' || *p == '\0') 21811558Srgrimes *cp = *endcp = p; 21821558Srgrimes else { 21831558Srgrimes *cp = p++; 21841558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 21851558Srgrimes p++; 21861558Srgrimes *endcp = p; 21871558Srgrimes } 21881558Srgrimes} 21891558Srgrimes 21901558Srgrimes/* 21911558Srgrimes * Get an exports file line. Skip over blank lines and handle line 21921558Srgrimes * continuations. 21931558Srgrimes */ 21941558Srgrimesint 21951558Srgrimesget_line() 21961558Srgrimes{ 21971558Srgrimes char *p, *cp; 219896622Siedowse size_t len; 21991558Srgrimes int totlen, cont_line; 22001558Srgrimes 22011558Srgrimes /* 22021558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 22031558Srgrimes */ 22041558Srgrimes p = line; 22051558Srgrimes totlen = 0; 22061558Srgrimes do { 220796622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 22081558Srgrimes return (0); 22091558Srgrimes cp = p + len - 1; 22101558Srgrimes cont_line = 0; 22111558Srgrimes while (cp >= p && 22121558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 22131558Srgrimes if (*cp == '\\') 22141558Srgrimes cont_line = 1; 22151558Srgrimes cp--; 22161558Srgrimes len--; 22171558Srgrimes } 221879117Sdd if (cont_line) { 221979117Sdd *++cp = ' '; 222079117Sdd len++; 222179117Sdd } 222296622Siedowse if (linesize < len + totlen + 1) { 222396622Siedowse linesize = len + totlen + 1; 222496622Siedowse line = realloc(line, linesize); 222596622Siedowse if (line == NULL) 222696622Siedowse out_of_mem(); 22271558Srgrimes } 222896622Siedowse memcpy(line + totlen, p, len); 222996622Siedowse totlen += len; 223096622Siedowse line[totlen] = '\0'; 22311558Srgrimes } while (totlen == 0 || cont_line); 22321558Srgrimes return (1); 22331558Srgrimes} 22341558Srgrimes 22351558Srgrimes/* 22361558Srgrimes * Parse a description of a credential. 22371558Srgrimes */ 22381558Srgrimesvoid 22391558Srgrimesparsecred(namelist, cr) 22401558Srgrimes char *namelist; 224172650Sgreen struct xucred *cr; 22421558Srgrimes{ 22431558Srgrimes char *name; 22441558Srgrimes int cnt; 22451558Srgrimes char *names; 22461558Srgrimes struct passwd *pw; 22471558Srgrimes struct group *gr; 2248136051Sstefanf gid_t groups[NGROUPS + 1]; 2249136051Sstefanf int ngroups; 22501558Srgrimes 225191354Sdd cr->cr_version = XUCRED_VERSION; 22521558Srgrimes /* 225337663Scharnier * Set up the unprivileged user. 22541558Srgrimes */ 22551558Srgrimes cr->cr_uid = -2; 22561558Srgrimes cr->cr_groups[0] = -2; 22571558Srgrimes cr->cr_ngroups = 1; 22581558Srgrimes /* 22591558Srgrimes * Get the user's password table entry. 22601558Srgrimes */ 22611558Srgrimes names = strsep(&namelist, " \t\n"); 22621558Srgrimes name = strsep(&names, ":"); 22631558Srgrimes if (isdigit(*name) || *name == '-') 22641558Srgrimes pw = getpwuid(atoi(name)); 22651558Srgrimes else 22661558Srgrimes pw = getpwnam(name); 22671558Srgrimes /* 22681558Srgrimes * Credentials specified as those of a user. 22691558Srgrimes */ 22701558Srgrimes if (names == NULL) { 22711558Srgrimes if (pw == NULL) { 227237663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 22731558Srgrimes return; 22741558Srgrimes } 22751558Srgrimes cr->cr_uid = pw->pw_uid; 22761558Srgrimes ngroups = NGROUPS + 1; 22771558Srgrimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 227837663Scharnier syslog(LOG_ERR, "too many groups"); 22791558Srgrimes /* 2280136051Sstefanf * Compress out duplicate. 22811558Srgrimes */ 22821558Srgrimes cr->cr_ngroups = ngroups - 1; 22831558Srgrimes cr->cr_groups[0] = groups[0]; 22841558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 22851558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 22861558Srgrimes return; 22871558Srgrimes } 22881558Srgrimes /* 22891558Srgrimes * Explicit credential specified as a colon separated list: 22901558Srgrimes * uid:gid:gid:... 22911558Srgrimes */ 22921558Srgrimes if (pw != NULL) 22931558Srgrimes cr->cr_uid = pw->pw_uid; 22941558Srgrimes else if (isdigit(*name) || *name == '-') 22951558Srgrimes cr->cr_uid = atoi(name); 22961558Srgrimes else { 229737663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 22981558Srgrimes return; 22991558Srgrimes } 23001558Srgrimes cr->cr_ngroups = 0; 23011558Srgrimes while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 23021558Srgrimes name = strsep(&names, ":"); 23031558Srgrimes if (isdigit(*name) || *name == '-') { 23041558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 23051558Srgrimes } else { 23061558Srgrimes if ((gr = getgrnam(name)) == NULL) { 230737663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 23081558Srgrimes continue; 23091558Srgrimes } 23101558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 23111558Srgrimes } 23121558Srgrimes } 23131558Srgrimes if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 231437663Scharnier syslog(LOG_ERR, "too many groups"); 23151558Srgrimes} 23161558Srgrimes 23171558Srgrimes#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 23181558Srgrimes/* 23191558Srgrimes * Routines that maintain the remote mounttab 23201558Srgrimes */ 23211558Srgrimesvoid 23221558Srgrimesget_mountlist() 23231558Srgrimes{ 23241558Srgrimes struct mountlist *mlp, **mlpp; 232523681Speter char *host, *dirp, *cp; 23261558Srgrimes char str[STRSIZ]; 23271558Srgrimes FILE *mlfile; 23281558Srgrimes 23291558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 233053117Sbillf if (errno == ENOENT) 233153117Sbillf return; 233253117Sbillf else { 233353117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 233453117Sbillf return; 233553117Sbillf } 23361558Srgrimes } 23371558Srgrimes mlpp = &mlhead; 23381558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 233923681Speter cp = str; 234023681Speter host = strsep(&cp, " \t\n"); 234123681Speter dirp = strsep(&cp, " \t\n"); 234223681Speter if (host == NULL || dirp == NULL) 23431558Srgrimes continue; 23441558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 234537663Scharnier if (mlp == (struct mountlist *)NULL) 234637663Scharnier out_of_mem(); 234723681Speter strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 234823681Speter mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 234923681Speter strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 235023681Speter mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 23511558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 23521558Srgrimes *mlpp = mlp; 23531558Srgrimes mlpp = &mlp->ml_next; 23541558Srgrimes } 23551558Srgrimes fclose(mlfile); 23561558Srgrimes} 23571558Srgrimes 235875635Siedowsevoid 235975635Siedowsedel_mlist(char *hostp, char *dirp) 23601558Srgrimes{ 23611558Srgrimes struct mountlist *mlp, **mlpp; 23621558Srgrimes struct mountlist *mlp2; 23631558Srgrimes FILE *mlfile; 23641558Srgrimes int fnd = 0; 23651558Srgrimes 23661558Srgrimes mlpp = &mlhead; 23671558Srgrimes mlp = mlhead; 23681558Srgrimes while (mlp) { 23691558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 23701558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 23711558Srgrimes fnd = 1; 23721558Srgrimes mlp2 = mlp; 23731558Srgrimes *mlpp = mlp = mlp->ml_next; 23741558Srgrimes free((caddr_t)mlp2); 23751558Srgrimes } else { 23761558Srgrimes mlpp = &mlp->ml_next; 23771558Srgrimes mlp = mlp->ml_next; 23781558Srgrimes } 23791558Srgrimes } 23801558Srgrimes if (fnd) { 23811558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 238237663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 23831558Srgrimes return; 23841558Srgrimes } 23851558Srgrimes mlp = mlhead; 23861558Srgrimes while (mlp) { 23871558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 23881558Srgrimes mlp = mlp->ml_next; 23891558Srgrimes } 23901558Srgrimes fclose(mlfile); 23911558Srgrimes } 23921558Srgrimes} 23931558Srgrimes 23941558Srgrimesvoid 23951558Srgrimesadd_mlist(hostp, dirp) 23961558Srgrimes char *hostp, *dirp; 23971558Srgrimes{ 23981558Srgrimes struct mountlist *mlp, **mlpp; 23991558Srgrimes FILE *mlfile; 24001558Srgrimes 24011558Srgrimes mlpp = &mlhead; 24021558Srgrimes mlp = mlhead; 24031558Srgrimes while (mlp) { 24041558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 24051558Srgrimes return; 24061558Srgrimes mlpp = &mlp->ml_next; 24071558Srgrimes mlp = mlp->ml_next; 24081558Srgrimes } 24091558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 241037663Scharnier if (mlp == (struct mountlist *)NULL) 241137663Scharnier out_of_mem(); 24121558Srgrimes strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 24131558Srgrimes mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 24141558Srgrimes strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 24151558Srgrimes mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 24161558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 24171558Srgrimes *mlpp = mlp; 24181558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 241937663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 24201558Srgrimes return; 24211558Srgrimes } 24221558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 24231558Srgrimes fclose(mlfile); 24241558Srgrimes} 24251558Srgrimes 24261558Srgrimes/* 24271558Srgrimes * Free up a group list. 24281558Srgrimes */ 24291558Srgrimesvoid 24301558Srgrimesfree_grp(grp) 24311558Srgrimes struct grouplist *grp; 24321558Srgrimes{ 24331558Srgrimes if (grp->gr_type == GT_HOST) { 243474462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 243574462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 24361558Srgrimes } else if (grp->gr_type == GT_NET) { 24371558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 24381558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 24391558Srgrimes } 24401558Srgrimes free((caddr_t)grp); 24411558Srgrimes} 24421558Srgrimes 24431558Srgrimes#ifdef DEBUG 24441558Srgrimesvoid 24451558SrgrimesSYSLOG(int pri, const char *fmt, ...) 24461558Srgrimes{ 24471558Srgrimes va_list ap; 24481558Srgrimes 24491558Srgrimes va_start(ap, fmt); 24501558Srgrimes vfprintf(stderr, fmt, ap); 24511558Srgrimes va_end(ap); 24521558Srgrimes} 24531558Srgrimes#endif /* DEBUG */ 24541558Srgrimes 24551558Srgrimes/* 24561558Srgrimes * Check options for consistency. 24571558Srgrimes */ 24581558Srgrimesint 24591558Srgrimescheck_options(dp) 24601558Srgrimes struct dirlist *dp; 24611558Srgrimes{ 24621558Srgrimes 24631558Srgrimes if (dp == (struct dirlist *)NULL) 24641558Srgrimes return (1); 246583653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 246683653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 24671558Srgrimes return (1); 24681558Srgrimes } 24691558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 247075801Siedowse syslog(LOG_ERR, "-mask requires -network"); 247175801Siedowse return (1); 24721558Srgrimes } 247375801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 247475801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 247575801Siedowse return (1); 247675801Siedowse } 247775801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 247875801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 247975801Siedowse return (1); 248075801Siedowse } 24811558Srgrimes if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 248245927Salex syslog(LOG_ERR, "-alldirs has multiple directories"); 24831558Srgrimes return (1); 24841558Srgrimes } 24851558Srgrimes return (0); 24861558Srgrimes} 24871558Srgrimes 24881558Srgrimes/* 24891558Srgrimes * Check an absolute directory path for any symbolic links. Return true 24901558Srgrimes */ 24911558Srgrimesint 24921558Srgrimescheck_dirpath(dirp) 24931558Srgrimes char *dirp; 24941558Srgrimes{ 24951558Srgrimes char *cp; 24961558Srgrimes int ret = 1; 24971558Srgrimes struct stat sb; 24981558Srgrimes 24991558Srgrimes cp = dirp + 1; 25001558Srgrimes while (*cp && ret) { 25011558Srgrimes if (*cp == '/') { 25021558Srgrimes *cp = '\0'; 25039336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 25041558Srgrimes ret = 0; 25051558Srgrimes *cp = '/'; 25061558Srgrimes } 25071558Srgrimes cp++; 25081558Srgrimes } 25099336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 25101558Srgrimes ret = 0; 25111558Srgrimes return (ret); 25121558Srgrimes} 25139336Sdfr 251475801Siedowse/* 251575801Siedowse * Make a netmask according to the specified prefix length. The ss_family 251675801Siedowse * and other non-address fields must be initialised before calling this. 251775801Siedowse */ 251875801Siedowseint 251975801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 252074462Salfred{ 252175801Siedowse u_char *p; 252275801Siedowse int bits, i, len; 252374462Salfred 252475801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 252575801Siedowse return (-1); 2526103949Smike if (bitlen > len * CHAR_BIT) 252775801Siedowse return (-1); 252874462Salfred 252975801Siedowse for (i = 0; i < len; i++) { 2530103949Smike bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 253175801Siedowse *p++ = (1 << bits) - 1; 253275801Siedowse bitlen -= bits; 253374462Salfred } 253475801Siedowse return 0; 253574462Salfred} 253674462Salfred 253775801Siedowse/* 253875801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 253975801Siedowse * is acceptable (i.e. of the form 1...10....0). 254075801Siedowse */ 254175801Siedowseint 254275801Siedowsecheckmask(struct sockaddr *sa) 254374462Salfred{ 254475801Siedowse u_char *mask; 254575801Siedowse int i, len; 254674462Salfred 254775801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 254875801Siedowse return (-1); 254975801Siedowse 255075801Siedowse for (i = 0; i < len; i++) 255175801Siedowse if (mask[i] != 0xff) 255275801Siedowse break; 255375801Siedowse if (i < len) { 255475801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 255575801Siedowse return (-1); 255675801Siedowse i++; 255774462Salfred } 255875801Siedowse for (; i < len; i++) 255975801Siedowse if (mask[i] != 0) 256075801Siedowse return (-1); 256175801Siedowse return (0); 256274462Salfred} 256374462Salfred 256475801Siedowse/* 256575801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 256675801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 256775801Siedowse * If samask is NULL, perform a full comparision. 256875801Siedowse */ 256975801Siedowseint 257075801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 257174462Salfred{ 257275801Siedowse unsigned char *p1, *p2, *mask; 257375801Siedowse int len, i; 257474462Salfred 257575801Siedowse if (sa1->sa_family != sa2->sa_family || 257675801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 257775801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 257875801Siedowse return (1); 257975801Siedowse 258075801Siedowse switch (sa1->sa_family) { 258174462Salfred case AF_INET6: 258275801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 258375801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 258475801Siedowse return (1); 258574462Salfred break; 258674462Salfred } 258774462Salfred 258875801Siedowse /* Simple binary comparison if no mask specified. */ 258975801Siedowse if (samask == NULL) 259075801Siedowse return (memcmp(p1, p2, len)); 259174462Salfred 259275801Siedowse /* Set up the mask, and do a mask-based comparison. */ 259375801Siedowse if (sa1->sa_family != samask->sa_family || 259475801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 259575801Siedowse return (1); 259674462Salfred 259775801Siedowse for (i = 0; i < len; i++) 259875801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 259975801Siedowse return (1); 260075801Siedowse return (0); 260174462Salfred} 260274462Salfred 260375801Siedowse/* 260475801Siedowse * Return a pointer to the part of the sockaddr that contains the 260575801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 260675801Siedowse * NULL if the address family is unknown. 260775801Siedowse */ 260875801Siedowsevoid * 260975801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 261075801Siedowse void *p; 261174462Salfred int len; 261274462Salfred 261375801Siedowse switch (sa->sa_family) { 261474462Salfred case AF_INET: 261575801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 261675801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 261774462Salfred break; 261874462Salfred case AF_INET6: 261975801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 262075801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 262174462Salfred break; 262274462Salfred default: 262375801Siedowse p = NULL; 262475801Siedowse len = 0; 262574462Salfred } 262674462Salfred 262775801Siedowse if (nbytes != NULL) 262875801Siedowse *nbytes = len; 262975801Siedowse return (p); 263074462Salfred} 263174462Salfred 263275754Siedowsevoid 263375754Siedowsehuphandler(int sig) 263475754Siedowse{ 263575754Siedowse got_sighup = 1; 263675754Siedowse} 263775754Siedowse 263874462Salfredvoid terminate(sig) 263974462Salfredint sig; 264074462Salfred{ 2641149433Spjd pidfile_remove(pfh); 264274792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 264374792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 264474462Salfred exit (0); 264574462Salfred} 2646