mountd.c revision 83653
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 * 3. All advertising materials mentioning features or use of this software 171558Srgrimes * must display the following acknowledgement: 181558Srgrimes * This product includes software developed by the University of 191558Srgrimes * California, Berkeley and its contributors. 201558Srgrimes * 4. Neither the name of the University nor the names of its contributors 211558Srgrimes * may be used to endorse or promote products derived from this software 221558Srgrimes * without specific prior written permission. 231558Srgrimes * 241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341558Srgrimes * SUCH DAMAGE. 351558Srgrimes */ 361558Srgrimes 371558Srgrimes#ifndef lint 3837663Scharnierstatic const char copyright[] = 391558Srgrimes"@(#) Copyright (c) 1989, 1993\n\ 401558Srgrimes The Regents of the University of California. All rights reserved.\n"; 412999Swollman#endif /*not lint*/ 421558Srgrimes 431558Srgrimes#ifndef lint 4437663Scharnier#if 0 4537663Scharnierstatic char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 4637663Scharnier#endif 472999Swollmanstatic const char rcsid[] = 4850476Speter "$FreeBSD: head/usr.sbin/mountd/mountd.c 83653 2001-09-18 23:34:44Z peter $"; 492999Swollman#endif /*not lint*/ 501558Srgrimes 511558Srgrimes#include <sys/param.h> 521558Srgrimes#include <sys/mount.h> 5374462Salfred#include <sys/fcntl.h> 541558Srgrimes#include <sys/stat.h> 551558Srgrimes#include <sys/syslog.h> 5624330Sguido#include <sys/sysctl.h> 571558Srgrimes 581558Srgrimes#include <rpc/rpc.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> 6523681Speter#include <ufs/ufs/ufsmount.h> 6677162Sru#include <fs/msdosfs/msdosfsmount.h> 6777223Sru#include <fs/ntfs/ntfsmount.h> 6823681Speter#include <isofs/cd9660/cd9660_mount.h> /* XXX need isofs in include */ 691558Srgrimes 701558Srgrimes#include <arpa/inet.h> 711558Srgrimes 721558Srgrimes#include <ctype.h> 7337663Scharnier#include <err.h> 741558Srgrimes#include <errno.h> 751558Srgrimes#include <grp.h> 761558Srgrimes#include <netdb.h> 771558Srgrimes#include <pwd.h> 781558Srgrimes#include <signal.h> 791558Srgrimes#include <stdio.h> 801558Srgrimes#include <stdlib.h> 811558Srgrimes#include <string.h> 821558Srgrimes#include <unistd.h> 831558Srgrimes#include "pathnames.h" 841558Srgrimes 851558Srgrimes#ifdef DEBUG 861558Srgrimes#include <stdarg.h> 871558Srgrimes#endif 881558Srgrimes 8974462Salfred#ifndef MOUNTDLOCK 9074462Salfred#define MOUNTDLOCK "/var/run/mountd.lock" 9174462Salfred#endif 9274462Salfred 931558Srgrimes/* 941558Srgrimes * Structures for keeping the mount list and export list 951558Srgrimes */ 961558Srgrimesstruct mountlist { 971558Srgrimes struct mountlist *ml_next; 981558Srgrimes char ml_host[RPCMNT_NAMELEN+1]; 991558Srgrimes char ml_dirp[RPCMNT_PATHLEN+1]; 1001558Srgrimes}; 1011558Srgrimes 1021558Srgrimesstruct dirlist { 1031558Srgrimes struct dirlist *dp_left; 1041558Srgrimes struct dirlist *dp_right; 1051558Srgrimes int dp_flag; 1061558Srgrimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 1071558Srgrimes char dp_dirp[1]; /* Actually malloc'd to size of dir */ 1081558Srgrimes}; 1091558Srgrimes/* dp_flag bits */ 1101558Srgrimes#define DP_DEFSET 0x1 1119336Sdfr#define DP_HOSTSET 0x2 1121558Srgrimes 1131558Srgrimesstruct exportlist { 1141558Srgrimes struct exportlist *ex_next; 1151558Srgrimes struct dirlist *ex_dirl; 1161558Srgrimes struct dirlist *ex_defdir; 1171558Srgrimes int ex_flag; 1181558Srgrimes fsid_t ex_fs; 1191558Srgrimes char *ex_fsdir; 12027447Sdfr char *ex_indexfile; 1211558Srgrimes}; 1221558Srgrimes/* ex_flag bits */ 1231558Srgrimes#define EX_LINKED 0x1 1241558Srgrimes 1251558Srgrimesstruct netmsk { 12674462Salfred struct sockaddr_storage nt_net; 12775801Siedowse struct sockaddr_storage nt_mask; 12842144Sdfr char *nt_name; 1291558Srgrimes}; 1301558Srgrimes 1311558Srgrimesunion grouptypes { 13274462Salfred struct addrinfo *gt_addrinfo; 1331558Srgrimes struct netmsk gt_net; 1341558Srgrimes}; 1351558Srgrimes 1361558Srgrimesstruct grouplist { 1371558Srgrimes int gr_type; 1381558Srgrimes union grouptypes gr_ptr; 1391558Srgrimes struct grouplist *gr_next; 1401558Srgrimes}; 1411558Srgrimes/* Group types */ 1421558Srgrimes#define GT_NULL 0x0 1431558Srgrimes#define GT_HOST 0x1 1441558Srgrimes#define GT_NET 0x2 14575641Siedowse#define GT_DEFAULT 0x3 1467401Swpaul#define GT_IGNORE 0x5 1471558Srgrimes 1481558Srgrimesstruct hostlist { 1499336Sdfr int ht_flag; /* Uses DP_xx bits */ 1501558Srgrimes struct grouplist *ht_grp; 1511558Srgrimes struct hostlist *ht_next; 1521558Srgrimes}; 1531558Srgrimes 1549336Sdfrstruct fhreturn { 1559336Sdfr int fhr_flag; 1569336Sdfr int fhr_vers; 1579336Sdfr nfsfh_t fhr_fh; 1589336Sdfr}; 1599336Sdfr 1601558Srgrimes/* Global defs */ 1611558Srgrimeschar *add_expdir __P((struct dirlist **, char *, int)); 1621558Srgrimesvoid add_dlist __P((struct dirlist **, struct dirlist *, 1639336Sdfr struct grouplist *, int)); 1641558Srgrimesvoid add_mlist __P((char *, char *)); 1651558Srgrimesint check_dirpath __P((char *)); 1661558Srgrimesint check_options __P((struct dirlist *)); 16775801Siedowseint checkmask(struct sockaddr *sa); 16874462Salfredint chk_host __P((struct dirlist *, struct sockaddr *, int *, int *)); 16975635Siedowsevoid del_mlist(char *hostp, char *dirp); 1701558Srgrimesstruct dirlist *dirp_search __P((struct dirlist *, char *)); 1711558Srgrimesint do_mount __P((struct exportlist *, struct grouplist *, int, 17272650Sgreen struct xucred *, char *, int, struct statfs *)); 1731558Srgrimesint do_opt __P((char **, char **, struct exportlist *, struct grouplist *, 17472650Sgreen int *, int *, struct xucred *)); 1751558Srgrimesstruct exportlist *ex_search __P((fsid_t *)); 1761558Srgrimesstruct exportlist *get_exp __P((void)); 1771558Srgrimesvoid free_dir __P((struct dirlist *)); 1781558Srgrimesvoid free_exp __P((struct exportlist *)); 1791558Srgrimesvoid free_grp __P((struct grouplist *)); 1801558Srgrimesvoid free_host __P((struct hostlist *)); 1811558Srgrimesvoid get_exportlist __P((void)); 1827401Swpaulint get_host __P((char *, struct grouplist *, struct grouplist *)); 1831558Srgrimesstruct hostlist *get_ht __P((void)); 1841558Srgrimesint get_line __P((void)); 1851558Srgrimesvoid get_mountlist __P((void)); 1861558Srgrimesint get_net __P((char *, struct netmsk *, int)); 1871558Srgrimesvoid getexp_err __P((struct exportlist *, struct grouplist *)); 1881558Srgrimesstruct grouplist *get_grp __P((void)); 1891558Srgrimesvoid hang_dirp __P((struct dirlist *, struct grouplist *, 1901558Srgrimes struct exportlist *, int)); 19175754Siedowsevoid huphandler(int sig); 19275801Siedowseint makemask(struct sockaddr_storage *ssp, int bitlen); 1931558Srgrimesvoid mntsrv __P((struct svc_req *, SVCXPRT *)); 1941558Srgrimesvoid nextfield __P((char **, char **)); 1951558Srgrimesvoid out_of_mem __P((void)); 19672650Sgreenvoid parsecred __P((char *, struct xucred *)); 1971558Srgrimesint put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *)); 19875801Siedowsevoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 19975801Siedowseint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 20075801Siedowse struct sockaddr *samask); 20174462Salfredint scan_tree __P((struct dirlist *, struct sockaddr *)); 20237663Scharnierstatic void usage __P((void)); 2031558Srgrimesint xdr_dir __P((XDR *, char *)); 2041558Srgrimesint xdr_explist __P((XDR *, caddr_t)); 2059336Sdfrint xdr_fhs __P((XDR *, caddr_t)); 2061558Srgrimesint xdr_mlist __P((XDR *, caddr_t)); 20774462Salfredvoid terminate __P((int)); 2081558Srgrimes 2091558Srgrimesstruct exportlist *exphead; 2101558Srgrimesstruct mountlist *mlhead; 2111558Srgrimesstruct grouplist *grphead; 2121558Srgrimeschar exname[MAXPATHLEN]; 21372650Sgreenstruct xucred def_anon = { 21472650Sgreen 0, 21572650Sgreen (uid_t)-2, 2161558Srgrimes 1, 21772650Sgreen { (gid_t)-2 }, 21872650Sgreen NULL 2191558Srgrimes}; 22025087Sdfrint force_v2 = 0; 2219336Sdfrint resvport_only = 1; 2229336Sdfrint dir_only = 1; 22331705Sguidoint log = 0; 22475754Siedowseint got_sighup = 0; 22574462Salfred 2261558Srgrimesint opt_flags; 22774462Salfredstatic int have_v6 = 1; 22874462Salfred#ifdef NI_WITHSCOPEID 22974462Salfredstatic const int ninumeric = NI_NUMERICHOST | NI_WITHSCOPEID; 23074462Salfred#else 23174462Salfredstatic const int ninumeric = NI_NUMERICHOST; 23274462Salfred#endif 23374462Salfred 23474462Salfredint mountdlockfd; 23575801Siedowse/* Bits for opt_flags above */ 2361558Srgrimes#define OP_MAPROOT 0x01 2371558Srgrimes#define OP_MAPALL 0x02 23883653Speter/* 0x4 free */ 2391558Srgrimes#define OP_MASK 0x08 2401558Srgrimes#define OP_NET 0x10 2411558Srgrimes#define OP_ALLDIRS 0x40 24275801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 24374462Salfred#define OP_MASKLEN 0x200 2441558Srgrimes 2451558Srgrimes#ifdef DEBUG 2461558Srgrimesint debug = 1; 24781911Skrisvoid SYSLOG __P((int, const char *, ...)) __printflike(2, 3); 2481558Srgrimes#define syslog SYSLOG 2491558Srgrimes#else 2501558Srgrimesint debug = 0; 2511558Srgrimes#endif 2521558Srgrimes 2531558Srgrimes/* 2541558Srgrimes * Mountd server for NFS mount protocol as described in: 2551558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 2561558Srgrimes * The optional arguments are the exports file name 2571558Srgrimes * default: _PATH_EXPORTS 2581558Srgrimes * and "-n" to allow nonroot mount. 2591558Srgrimes */ 2601558Srgrimesint 2611558Srgrimesmain(argc, argv) 2621558Srgrimes int argc; 2631558Srgrimes char **argv; 2641558Srgrimes{ 26575754Siedowse fd_set readfds; 26674462Salfred SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; 26774462Salfred struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 26874462Salfred int udpsock, tcpsock, udp6sock, tcp6sock; 26974462Salfred int xcreated = 0, s; 27074462Salfred int one = 1; 27132656Sbde int c, error, mib[3]; 27223681Speter struct vfsconf vfc; 2731558Srgrimes 27475635Siedowse udp6conf = tcp6conf = NULL; 27575635Siedowse udp6sock = tcp6sock = NULL; 27675635Siedowse 27774462Salfred /* Check that another mountd isn't already running. */ 27874462Salfred if ((mountdlockfd = (open(MOUNTDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) 27974462Salfred err(1, "%s", MOUNTDLOCK); 28074462Salfred 28174462Salfred if(flock(mountdlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) 28274462Salfred errx(1, "another rpc.mountd is already running. Aborting"); 28374462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 28474462Salfred if (s < 0) 28574462Salfred have_v6 = 0; 28674462Salfred else 28774462Salfred close(s); 28823681Speter error = getvfsbyname("nfs", &vfc); 28923681Speter if (error && vfsisloadable("nfs")) { 2902999Swollman if(vfsload("nfs")) 2912999Swollman err(1, "vfsload(nfs)"); 2922999Swollman endvfsent(); /* flush cache */ 29323681Speter error = getvfsbyname("nfs", &vfc); 2942999Swollman } 29523681Speter if (error) 2962999Swollman errx(1, "NFS support is not available in the running kernel"); 2972999Swollman 29831665Sguido while ((c = getopt(argc, argv, "2dlnr")) != -1) 2991558Srgrimes switch (c) { 30025087Sdfr case '2': 30125087Sdfr force_v2 = 1; 30225087Sdfr break; 3039336Sdfr case 'n': 3049336Sdfr resvport_only = 0; 3059336Sdfr break; 3069336Sdfr case 'r': 3079336Sdfr dir_only = 0; 3089336Sdfr break; 3098688Sphk case 'd': 3108688Sphk debug = debug ? 0 : 1; 3118688Sphk break; 31231656Sguido case 'l': 31331656Sguido log = 1; 31431656Sguido break; 3151558Srgrimes default: 31637663Scharnier usage(); 3171558Srgrimes }; 3181558Srgrimes argc -= optind; 3191558Srgrimes argv += optind; 3201558Srgrimes grphead = (struct grouplist *)NULL; 3211558Srgrimes exphead = (struct exportlist *)NULL; 3221558Srgrimes mlhead = (struct mountlist *)NULL; 3231558Srgrimes if (argc == 1) { 3241558Srgrimes strncpy(exname, *argv, MAXPATHLEN-1); 3251558Srgrimes exname[MAXPATHLEN-1] = '\0'; 3261558Srgrimes } else 3271558Srgrimes strcpy(exname, _PATH_EXPORTS); 3281558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 3291558Srgrimes if (debug) 33037663Scharnier warnx("getting export list"); 3311558Srgrimes get_exportlist(); 3321558Srgrimes if (debug) 33337663Scharnier warnx("getting mount list"); 3341558Srgrimes get_mountlist(); 3351558Srgrimes if (debug) 33637663Scharnier warnx("here we go"); 3371558Srgrimes if (debug == 0) { 3381558Srgrimes daemon(0, 0); 3391558Srgrimes signal(SIGINT, SIG_IGN); 3401558Srgrimes signal(SIGQUIT, SIG_IGN); 3411558Srgrimes } 34275754Siedowse signal(SIGHUP, huphandler); 34374462Salfred signal(SIGTERM, terminate); 3441558Srgrimes { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 3451558Srgrimes if (pidfile != NULL) { 3461558Srgrimes fprintf(pidfile, "%d\n", getpid()); 3471558Srgrimes fclose(pidfile); 3481558Srgrimes } 3491558Srgrimes } 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"); 35674791Salfred if (!have_v6) 35774791Salfred goto skip_v6; 35874462Salfred udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 35974462Salfred tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 36074462Salfred /* 36174462Salfred * We're doing host-based access checks here, so don't allow 36274462Salfred * v4-in-v6 to confuse things. The kernel will disable it 36374462Salfred * by default on NFS sockets too. 36474462Salfred */ 36574462Salfred if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6, 36674462Salfred IPV6_BINDV6ONLY, &one, sizeof one) < 0){ 36774462Salfred syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 36874462Salfred exit(1); 36974462Salfred } 37074462Salfred if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6, 37174462Salfred IPV6_BINDV6ONLY, &one, sizeof one) < 0){ 37274462Salfred syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 37374462Salfred exit(1); 37474462Salfred } 37574462Salfred udp6conf = getnetconfigent("udp6"); 37674462Salfred tcp6conf = getnetconfigent("tcp6"); 37774791Salfred 37874791Salfredskip_v6: 37924759Sguido if (!resvport_only) { 38024759Sguido mib[0] = CTL_VFS; 38132656Sbde mib[1] = vfc.vfc_typenum; 38224759Sguido mib[2] = NFS_NFSPRIVPORT; 38324759Sguido if (sysctl(mib, 3, NULL, NULL, &resvport_only, 38424759Sguido sizeof(resvport_only)) != 0 && errno != ENOENT) { 38524759Sguido syslog(LOG_ERR, "sysctl: %m"); 38624759Sguido exit(1); 38724759Sguido } 38824330Sguido } 3899202Srgrimes if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL || 3909202Srgrimes (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) { 39137663Scharnier syslog(LOG_ERR, "can't create socket"); 3921558Srgrimes exit(1); 3931558Srgrimes } 39474462Salfred if (udpsock != -1 && udpconf != NULL) { 39574462Salfred bindresvport(udpsock, NULL); 39674462Salfred udptransp = svc_dg_create(udpsock, 0, 0); 39774462Salfred if (udptransp != NULL) { 39874462Salfred if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, 39974462Salfred mntsrv, udpconf)) 40074462Salfred syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service"); 40174462Salfred else 40274462Salfred xcreated++; 40374462Salfred if (!force_v2) { 40474462Salfred if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3, 40574462Salfred mntsrv, udpconf)) 40674462Salfred syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service"); 40774462Salfred else 40874462Salfred xcreated++; 40974462Salfred } 41074462Salfred } else 41174462Salfred syslog(LOG_WARNING, "can't create UDP services"); 41274462Salfred 41374462Salfred } 41474462Salfred if (tcpsock != -1 && tcpconf != NULL) { 41574462Salfred bindresvport(tcpsock, NULL); 41674462Salfred listen(tcpsock, SOMAXCONN); 41774462Salfred tcptransp = svc_vc_create(tcpsock, 0, 0); 41874462Salfred if (tcptransp != NULL) { 41974462Salfred if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1, 42074462Salfred mntsrv, tcpconf)) 42174462Salfred syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service"); 42274462Salfred else 42374462Salfred xcreated++; 42474462Salfred if (!force_v2) { 42574462Salfred if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3, 42674462Salfred mntsrv, tcpconf)) 42774462Salfred syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service"); 42874462Salfred else 42974462Salfred xcreated++; 43074462Salfred } 43174462Salfred } else 43274462Salfred syslog(LOG_WARNING, "can't create TCP service"); 43374462Salfred 43474462Salfred } 43574791Salfred if (have_v6 && udp6sock != -1 && udp6conf != NULL) { 43674462Salfred bindresvport(udp6sock, NULL); 43774462Salfred udp6transp = svc_dg_create(udp6sock, 0, 0); 43874462Salfred if (udp6transp != NULL) { 43974462Salfred if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, 44074462Salfred mntsrv, udp6conf)) 44174462Salfred syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service"); 44274462Salfred else 44374462Salfred xcreated++; 44474462Salfred if (!force_v2) { 44574462Salfred if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3, 44674462Salfred mntsrv, udp6conf)) 44774462Salfred syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service"); 44874462Salfred else 44974462Salfred xcreated++; 45074462Salfred } 45174462Salfred } else 45274462Salfred syslog(LOG_WARNING, "can't create UDP6 service"); 45374462Salfred 45474462Salfred } 45574791Salfred if (have_v6 && tcp6sock != -1 && tcp6conf != NULL) { 45674462Salfred bindresvport(tcp6sock, NULL); 45774462Salfred listen(tcp6sock, SOMAXCONN); 45874462Salfred tcp6transp = svc_vc_create(tcp6sock, 0, 0); 45974462Salfred if (tcp6transp != NULL) { 46074462Salfred if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1, 46174462Salfred mntsrv, tcp6conf)) 46274462Salfred syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service"); 46374462Salfred else 46474462Salfred xcreated++; 46574462Salfred if (!force_v2) { 46674462Salfred if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3, 46774462Salfred mntsrv, tcp6conf)) 46874462Salfred syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service"); 46974462Salfred else 47074462Salfred xcreated++; 47174462Salfred } 47274462Salfred } else 47374462Salfred syslog(LOG_WARNING, "can't create TCP6 service"); 47474462Salfred 47574462Salfred } 47674462Salfred if (xcreated == 0) { 47774462Salfred syslog(LOG_ERR, "could not create any services"); 4781558Srgrimes exit(1); 4791558Srgrimes } 48075754Siedowse 48175754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 48275754Siedowse for (;;) { 48375754Siedowse if (got_sighup) { 48475754Siedowse get_exportlist(); 48575754Siedowse got_sighup = 0; 48675754Siedowse } 48775754Siedowse readfds = svc_fdset; 48875754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 48975754Siedowse case -1: 49075754Siedowse if (errno == EINTR) 49175754Siedowse continue; 49275754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 49375754Siedowse exit(1); 49475754Siedowse case 0: 49575754Siedowse continue; 49675754Siedowse default: 49775754Siedowse svc_getreqset(&readfds); 49875754Siedowse } 49975754Siedowse } 5001558Srgrimes} 5011558Srgrimes 50237663Scharnierstatic void 50337663Scharnierusage() 50437663Scharnier{ 50537663Scharnier fprintf(stderr, 50637663Scharnier "usage: mountd [-2] [-d] [-l] [-n] [-r] [export_file]\n"); 50737663Scharnier exit(1); 50837663Scharnier} 50937663Scharnier 5101558Srgrimes/* 5111558Srgrimes * The mount rpc service 5121558Srgrimes */ 5131558Srgrimesvoid 5141558Srgrimesmntsrv(rqstp, transp) 5151558Srgrimes struct svc_req *rqstp; 5161558Srgrimes SVCXPRT *transp; 5171558Srgrimes{ 5181558Srgrimes struct exportlist *ep; 5191558Srgrimes struct dirlist *dp; 5209336Sdfr struct fhreturn fhr; 5211558Srgrimes struct stat stb; 5221558Srgrimes struct statfs fsb; 52374462Salfred struct addrinfo *ai; 52474462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 52574462Salfred int lookup_failed = 1; 52674462Salfred struct sockaddr *saddr; 5279336Sdfr u_short sport; 52823681Speter char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 52928911Sguido int bad = 0, defset, hostset; 5309336Sdfr sigset_t sighup_mask; 5311558Srgrimes 5329336Sdfr sigemptyset(&sighup_mask); 5339336Sdfr sigaddset(&sighup_mask, SIGHUP); 53474462Salfred saddr = svc_getrpccaller(transp)->buf; 53574462Salfred switch (saddr->sa_family) { 53674462Salfred case AF_INET6: 53775635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 53874462Salfred break; 53974462Salfred case AF_INET: 54075635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 54174462Salfred break; 54274462Salfred default: 54374462Salfred syslog(LOG_ERR, "request from unknown address family"); 54474462Salfred return; 54574462Salfred } 54674462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 54774462Salfred NULL, 0, 0); 54874462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 54974462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 55074462Salfred ai = NULL; 5511558Srgrimes switch (rqstp->rq_proc) { 5521558Srgrimes case NULLPROC: 5531558Srgrimes if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 55437663Scharnier syslog(LOG_ERR, "can't send reply"); 5551558Srgrimes return; 5561558Srgrimes case RPCMNT_MOUNT: 5579336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 55831656Sguido syslog(LOG_NOTICE, 55931656Sguido "mount request from %s from unprivileged port", 56074462Salfred numerichost); 5611558Srgrimes svcerr_weakauth(transp); 5621558Srgrimes return; 5631558Srgrimes } 5641558Srgrimes if (!svc_getargs(transp, xdr_dir, rpcpath)) { 56531656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 56674462Salfred numerichost); 5671558Srgrimes svcerr_decode(transp); 5681558Srgrimes return; 5691558Srgrimes } 5701558Srgrimes 5711558Srgrimes /* 5721558Srgrimes * Get the real pathname and make sure it is a directory 5739336Sdfr * or a regular file if the -r option was specified 5749336Sdfr * and it exists. 5751558Srgrimes */ 57651968Salfred if (realpath(rpcpath, dirpath) == NULL || 5771558Srgrimes stat(dirpath, &stb) < 0 || 5789336Sdfr (!S_ISDIR(stb.st_mode) && 57974462Salfred (dir_only || !S_ISREG(stb.st_mode))) || 5801558Srgrimes statfs(dirpath, &fsb) < 0) { 5811558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 58231656Sguido syslog(LOG_NOTICE, 58337663Scharnier "mount request from %s for non existent path %s", 58474462Salfred numerichost, dirpath); 5851558Srgrimes if (debug) 58637663Scharnier warnx("stat failed on %s", dirpath); 58728911Sguido bad = ENOENT; /* We will send error reply later */ 5881558Srgrimes } 5891558Srgrimes 5901558Srgrimes /* Check in the exports list */ 5919336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 5921558Srgrimes ep = ex_search(&fsb.f_fsid); 5939336Sdfr hostset = defset = 0; 5949336Sdfr if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 5951558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 59674462Salfred chk_host(dp, saddr, &defset, &hostset)) || 59774462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 59874462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 59928911Sguido if (bad) { 60028911Sguido if (!svc_sendreply(transp, xdr_long, 60128911Sguido (caddr_t)&bad)) 60237663Scharnier syslog(LOG_ERR, "can't send reply"); 60328911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 60428911Sguido return; 60528911Sguido } 6069336Sdfr if (hostset & DP_HOSTSET) 6079336Sdfr fhr.fhr_flag = hostset; 6089336Sdfr else 6099336Sdfr fhr.fhr_flag = defset; 6109336Sdfr fhr.fhr_vers = rqstp->rq_vers; 6111558Srgrimes /* Get the file handle */ 61223681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 6139336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 6141558Srgrimes bad = errno; 61537663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 6161558Srgrimes if (!svc_sendreply(transp, xdr_long, 6171558Srgrimes (caddr_t)&bad)) 61837663Scharnier syslog(LOG_ERR, "can't send reply"); 6199336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 6201558Srgrimes return; 6211558Srgrimes } 6229336Sdfr if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr)) 62337663Scharnier syslog(LOG_ERR, "can't send reply"); 62474462Salfred if (!lookup_failed) 62574462Salfred add_mlist(host, dirpath); 6261558Srgrimes else 62774462Salfred add_mlist(numerichost, dirpath); 6281558Srgrimes if (debug) 62937663Scharnier warnx("mount successful"); 63031656Sguido if (log) 63131656Sguido syslog(LOG_NOTICE, 63231656Sguido "mount request succeeded from %s for %s", 63374462Salfred numerichost, dirpath); 63431656Sguido } else { 6351558Srgrimes bad = EACCES; 63631656Sguido syslog(LOG_NOTICE, 63731656Sguido "mount request denied from %s for %s", 63874462Salfred numerichost, dirpath); 63931656Sguido } 64028911Sguido 64128911Sguido if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 64237663Scharnier syslog(LOG_ERR, "can't send reply"); 6439336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 6441558Srgrimes return; 6451558Srgrimes case RPCMNT_DUMP: 6461558Srgrimes if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) 64737663Scharnier syslog(LOG_ERR, "can't send reply"); 64831656Sguido else if (log) 64931656Sguido syslog(LOG_NOTICE, 65031656Sguido "dump request succeeded from %s", 65174462Salfred numerichost); 6521558Srgrimes return; 6531558Srgrimes case RPCMNT_UMOUNT: 6549336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 65531656Sguido syslog(LOG_NOTICE, 65631656Sguido "umount request from %s from unprivileged port", 65774462Salfred numerichost); 6581558Srgrimes svcerr_weakauth(transp); 6591558Srgrimes return; 6601558Srgrimes } 66151968Salfred if (!svc_getargs(transp, xdr_dir, rpcpath)) { 66231656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 66374462Salfred numerichost); 6641558Srgrimes svcerr_decode(transp); 6651558Srgrimes return; 6661558Srgrimes } 66751968Salfred if (realpath(rpcpath, dirpath) == NULL) { 66851968Salfred syslog(LOG_NOTICE, "umount request from %s " 66951968Salfred "for non existent path %s", 67074462Salfred numerichost, dirpath); 67151968Salfred } 6721558Srgrimes if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 67337663Scharnier syslog(LOG_ERR, "can't send reply"); 67474462Salfred if (!lookup_failed) 67575635Siedowse del_mlist(host, dirpath); 67675635Siedowse del_mlist(numerichost, dirpath); 67731656Sguido if (log) 67831656Sguido syslog(LOG_NOTICE, 67931656Sguido "umount request succeeded from %s for %s", 68074462Salfred numerichost, dirpath); 6811558Srgrimes return; 6821558Srgrimes case RPCMNT_UMNTALL: 6839336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 68431656Sguido syslog(LOG_NOTICE, 68531656Sguido "umountall request from %s from unprivileged port", 68674462Salfred numerichost); 6871558Srgrimes svcerr_weakauth(transp); 6881558Srgrimes return; 6891558Srgrimes } 6901558Srgrimes if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 69137663Scharnier syslog(LOG_ERR, "can't send reply"); 69274462Salfred if (!lookup_failed) 69375635Siedowse del_mlist(host, NULL); 69475635Siedowse del_mlist(numerichost, NULL); 69531656Sguido if (log) 69631656Sguido syslog(LOG_NOTICE, 69731656Sguido "umountall request succeeded from %s", 69874462Salfred numerichost); 6991558Srgrimes return; 7001558Srgrimes case RPCMNT_EXPORT: 7011558Srgrimes if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) 70237663Scharnier syslog(LOG_ERR, "can't send reply"); 70331656Sguido if (log) 70431656Sguido syslog(LOG_NOTICE, 70531656Sguido "export request succeeded from %s", 70674462Salfred numerichost); 7071558Srgrimes return; 7081558Srgrimes default: 7091558Srgrimes svcerr_noproc(transp); 7101558Srgrimes return; 7111558Srgrimes } 7121558Srgrimes} 7131558Srgrimes 7141558Srgrimes/* 7151558Srgrimes * Xdr conversion for a dirpath string 7161558Srgrimes */ 7171558Srgrimesint 7181558Srgrimesxdr_dir(xdrsp, dirp) 7191558Srgrimes XDR *xdrsp; 7201558Srgrimes char *dirp; 7211558Srgrimes{ 7221558Srgrimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 7231558Srgrimes} 7241558Srgrimes 7251558Srgrimes/* 7269336Sdfr * Xdr routine to generate file handle reply 7271558Srgrimes */ 7281558Srgrimesint 7299336Sdfrxdr_fhs(xdrsp, cp) 7301558Srgrimes XDR *xdrsp; 7319336Sdfr caddr_t cp; 7321558Srgrimes{ 7339336Sdfr register struct fhreturn *fhrp = (struct fhreturn *)cp; 7349336Sdfr u_long ok = 0, len, auth; 7351558Srgrimes 7361558Srgrimes if (!xdr_long(xdrsp, &ok)) 7371558Srgrimes return (0); 7389336Sdfr switch (fhrp->fhr_vers) { 7399336Sdfr case 1: 7409336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 7419336Sdfr case 3: 7429336Sdfr len = NFSX_V3FH; 7439336Sdfr if (!xdr_long(xdrsp, &len)) 7449336Sdfr return (0); 7459336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 7469336Sdfr return (0); 74783653Speter auth = RPCAUTH_UNIX; 7489336Sdfr len = 1; 7499336Sdfr if (!xdr_long(xdrsp, &len)) 7509336Sdfr return (0); 7519336Sdfr return (xdr_long(xdrsp, &auth)); 7529336Sdfr }; 7539336Sdfr return (0); 7541558Srgrimes} 7551558Srgrimes 7561558Srgrimesint 7571558Srgrimesxdr_mlist(xdrsp, cp) 7581558Srgrimes XDR *xdrsp; 7591558Srgrimes caddr_t cp; 7601558Srgrimes{ 7611558Srgrimes struct mountlist *mlp; 7621558Srgrimes int true = 1; 7631558Srgrimes int false = 0; 7641558Srgrimes char *strp; 7651558Srgrimes 7661558Srgrimes mlp = mlhead; 7671558Srgrimes while (mlp) { 7681558Srgrimes if (!xdr_bool(xdrsp, &true)) 7691558Srgrimes return (0); 7701558Srgrimes strp = &mlp->ml_host[0]; 7711558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 7721558Srgrimes return (0); 7731558Srgrimes strp = &mlp->ml_dirp[0]; 7741558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 7751558Srgrimes return (0); 7761558Srgrimes mlp = mlp->ml_next; 7771558Srgrimes } 7781558Srgrimes if (!xdr_bool(xdrsp, &false)) 7791558Srgrimes return (0); 7801558Srgrimes return (1); 7811558Srgrimes} 7821558Srgrimes 7831558Srgrimes/* 7841558Srgrimes * Xdr conversion for export list 7851558Srgrimes */ 7861558Srgrimesint 7871558Srgrimesxdr_explist(xdrsp, cp) 7881558Srgrimes XDR *xdrsp; 7891558Srgrimes caddr_t cp; 7901558Srgrimes{ 7911558Srgrimes struct exportlist *ep; 7921558Srgrimes int false = 0; 7939336Sdfr int putdef; 7949336Sdfr sigset_t sighup_mask; 7951558Srgrimes 7969336Sdfr sigemptyset(&sighup_mask); 7979336Sdfr sigaddset(&sighup_mask, SIGHUP); 7989336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 7991558Srgrimes ep = exphead; 8001558Srgrimes while (ep) { 8011558Srgrimes putdef = 0; 8021558Srgrimes if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 8031558Srgrimes goto errout; 8041558Srgrimes if (ep->ex_defdir && putdef == 0 && 8051558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 8061558Srgrimes &putdef)) 8071558Srgrimes goto errout; 8081558Srgrimes ep = ep->ex_next; 8091558Srgrimes } 8109336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8111558Srgrimes if (!xdr_bool(xdrsp, &false)) 8121558Srgrimes return (0); 8131558Srgrimes return (1); 8141558Srgrimeserrout: 8159336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8161558Srgrimes return (0); 8171558Srgrimes} 8181558Srgrimes 8191558Srgrimes/* 8201558Srgrimes * Called from xdr_explist() to traverse the tree and export the 8211558Srgrimes * directory paths. 8221558Srgrimes */ 8231558Srgrimesint 8241558Srgrimesput_exlist(dp, xdrsp, adp, putdefp) 8251558Srgrimes struct dirlist *dp; 8261558Srgrimes XDR *xdrsp; 8271558Srgrimes struct dirlist *adp; 8281558Srgrimes int *putdefp; 8291558Srgrimes{ 8301558Srgrimes struct grouplist *grp; 8311558Srgrimes struct hostlist *hp; 8321558Srgrimes int true = 1; 8331558Srgrimes int false = 0; 8341558Srgrimes int gotalldir = 0; 8351558Srgrimes char *strp; 8361558Srgrimes 8371558Srgrimes if (dp) { 8381558Srgrimes if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 8391558Srgrimes return (1); 8401558Srgrimes if (!xdr_bool(xdrsp, &true)) 8411558Srgrimes return (1); 8421558Srgrimes strp = dp->dp_dirp; 8431558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 8441558Srgrimes return (1); 8451558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 8461558Srgrimes gotalldir = 1; 8471558Srgrimes *putdefp = 1; 8481558Srgrimes } 8491558Srgrimes if ((dp->dp_flag & DP_DEFSET) == 0 && 8501558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 8511558Srgrimes hp = dp->dp_hosts; 8521558Srgrimes while (hp) { 8531558Srgrimes grp = hp->ht_grp; 8541558Srgrimes if (grp->gr_type == GT_HOST) { 8551558Srgrimes if (!xdr_bool(xdrsp, &true)) 8561558Srgrimes return (1); 85774462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 8588871Srgrimes if (!xdr_string(xdrsp, &strp, 8591558Srgrimes RPCMNT_NAMELEN)) 8601558Srgrimes return (1); 8611558Srgrimes } else if (grp->gr_type == GT_NET) { 8621558Srgrimes if (!xdr_bool(xdrsp, &true)) 8631558Srgrimes return (1); 8641558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 8658871Srgrimes if (!xdr_string(xdrsp, &strp, 8661558Srgrimes RPCMNT_NAMELEN)) 8671558Srgrimes return (1); 8681558Srgrimes } 8691558Srgrimes hp = hp->ht_next; 8701558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 8711558Srgrimes hp = adp->dp_hosts; 8721558Srgrimes gotalldir = 0; 8731558Srgrimes } 8741558Srgrimes } 8751558Srgrimes } 8761558Srgrimes if (!xdr_bool(xdrsp, &false)) 8771558Srgrimes return (1); 8781558Srgrimes if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 8791558Srgrimes return (1); 8801558Srgrimes } 8811558Srgrimes return (0); 8821558Srgrimes} 8831558Srgrimes 8841558Srgrimes#define LINESIZ 10240 8851558Srgrimeschar line[LINESIZ]; 8861558SrgrimesFILE *exp_file; 8871558Srgrimes 8881558Srgrimes/* 8891558Srgrimes * Get the export list 8901558Srgrimes */ 8911558Srgrimesvoid 8921558Srgrimesget_exportlist() 8931558Srgrimes{ 8941558Srgrimes struct exportlist *ep, *ep2; 8951558Srgrimes struct grouplist *grp, *tgrp; 8961558Srgrimes struct exportlist **epp; 8971558Srgrimes struct dirlist *dirhead; 8981558Srgrimes struct statfs fsb, *fsp; 89972650Sgreen struct xucred anon; 9001558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 9011558Srgrimes int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 9021558Srgrimes 90351968Salfred dirp = NULL; 90451968Salfred dirplen = 0; 90551968Salfred 9061558Srgrimes /* 9071558Srgrimes * First, get rid of the old list 9081558Srgrimes */ 9091558Srgrimes ep = exphead; 9101558Srgrimes while (ep) { 9111558Srgrimes ep2 = ep; 9121558Srgrimes ep = ep->ex_next; 9131558Srgrimes free_exp(ep2); 9141558Srgrimes } 9151558Srgrimes exphead = (struct exportlist *)NULL; 9161558Srgrimes 9171558Srgrimes grp = grphead; 9181558Srgrimes while (grp) { 9191558Srgrimes tgrp = grp; 9201558Srgrimes grp = grp->gr_next; 9211558Srgrimes free_grp(tgrp); 9221558Srgrimes } 9231558Srgrimes grphead = (struct grouplist *)NULL; 9241558Srgrimes 9251558Srgrimes /* 9261558Srgrimes * And delete exports that are in the kernel for all local 9271558Srgrimes * file systems. 9281558Srgrimes * XXX: Should know how to handle all local exportable file systems 92923681Speter * instead of just "ufs". 9301558Srgrimes */ 9311558Srgrimes num = getmntinfo(&fsp, MNT_NOWAIT); 9321558Srgrimes for (i = 0; i < num; i++) { 9331558Srgrimes union { 9341558Srgrimes struct ufs_args ua; 9351558Srgrimes struct iso_args ia; 9369336Sdfr struct msdosfs_args da; 93754093Ssemenu struct ntfs_args na; 9381558Srgrimes } targs; 9391558Srgrimes 94077435Sphk if (!strcmp(fsp->f_fstypename, "ufs") || 94177577Sru !strcmp(fsp->f_fstypename, "msdosfs") || 94254093Ssemenu !strcmp(fsp->f_fstypename, "ntfs") || 94323681Speter !strcmp(fsp->f_fstypename, "cd9660")) { 9449336Sdfr targs.ua.fspec = NULL; 9459336Sdfr targs.ua.export.ex_flags = MNT_DELEXPORT; 9469336Sdfr if (mount(fsp->f_fstypename, fsp->f_mntonname, 94777405Siedowse fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0 && 94877405Siedowse errno != ENOENT) 94977405Siedowse syslog(LOG_ERR, 95077405Siedowse "can't delete exports for %s: %m", 95174462Salfred fsp->f_mntonname); 9521558Srgrimes } 9531558Srgrimes fsp++; 9541558Srgrimes } 9551558Srgrimes 9561558Srgrimes /* 9571558Srgrimes * Read in the exports file and build the list, calling 9581558Srgrimes * mount() as we go along to push the export rules into the kernel. 9591558Srgrimes */ 9601558Srgrimes if ((exp_file = fopen(exname, "r")) == NULL) { 96137663Scharnier syslog(LOG_ERR, "can't open %s", exname); 9621558Srgrimes exit(2); 9631558Srgrimes } 9641558Srgrimes dirhead = (struct dirlist *)NULL; 9651558Srgrimes while (get_line()) { 9661558Srgrimes if (debug) 96737663Scharnier warnx("got line %s", line); 9681558Srgrimes cp = line; 9691558Srgrimes nextfield(&cp, &endcp); 9701558Srgrimes if (*cp == '#') 9711558Srgrimes goto nextline; 9721558Srgrimes 9731558Srgrimes /* 9741558Srgrimes * Set defaults. 9751558Srgrimes */ 9761558Srgrimes has_host = FALSE; 9771558Srgrimes anon = def_anon; 9781558Srgrimes exflags = MNT_EXPORTED; 9791558Srgrimes got_nondir = 0; 9801558Srgrimes opt_flags = 0; 9811558Srgrimes ep = (struct exportlist *)NULL; 9821558Srgrimes 9831558Srgrimes /* 9841558Srgrimes * Create new exports list entry 9851558Srgrimes */ 9861558Srgrimes len = endcp-cp; 9871558Srgrimes tgrp = grp = get_grp(); 9881558Srgrimes while (len > 0) { 9891558Srgrimes if (len > RPCMNT_NAMELEN) { 9901558Srgrimes getexp_err(ep, tgrp); 9911558Srgrimes goto nextline; 9921558Srgrimes } 9931558Srgrimes if (*cp == '-') { 9941558Srgrimes if (ep == (struct exportlist *)NULL) { 9951558Srgrimes getexp_err(ep, tgrp); 9961558Srgrimes goto nextline; 9971558Srgrimes } 9981558Srgrimes if (debug) 99937663Scharnier warnx("doing opt %s", cp); 10001558Srgrimes got_nondir = 1; 10011558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 10021558Srgrimes &exflags, &anon)) { 10031558Srgrimes getexp_err(ep, tgrp); 10041558Srgrimes goto nextline; 10051558Srgrimes } 10061558Srgrimes } else if (*cp == '/') { 10071558Srgrimes savedc = *endcp; 10081558Srgrimes *endcp = '\0'; 10091558Srgrimes if (check_dirpath(cp) && 10101558Srgrimes statfs(cp, &fsb) >= 0) { 10111558Srgrimes if (got_nondir) { 101237663Scharnier syslog(LOG_ERR, "dirs must be first"); 10131558Srgrimes getexp_err(ep, tgrp); 10141558Srgrimes goto nextline; 10151558Srgrimes } 10161558Srgrimes if (ep) { 10171558Srgrimes if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 10181558Srgrimes ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 10191558Srgrimes getexp_err(ep, tgrp); 10201558Srgrimes goto nextline; 10211558Srgrimes } 10221558Srgrimes } else { 10231558Srgrimes /* 10241558Srgrimes * See if this directory is already 10251558Srgrimes * in the list. 10261558Srgrimes */ 10271558Srgrimes ep = ex_search(&fsb.f_fsid); 10281558Srgrimes if (ep == (struct exportlist *)NULL) { 10291558Srgrimes ep = get_exp(); 10301558Srgrimes ep->ex_fs = fsb.f_fsid; 10311558Srgrimes ep->ex_fsdir = (char *) 10321558Srgrimes malloc(strlen(fsb.f_mntonname) + 1); 10331558Srgrimes if (ep->ex_fsdir) 10341558Srgrimes strcpy(ep->ex_fsdir, 10351558Srgrimes fsb.f_mntonname); 10361558Srgrimes else 10371558Srgrimes out_of_mem(); 10381558Srgrimes if (debug) 103974462Salfred warnx("making new ep fs=0x%x,0x%x", 104074462Salfred fsb.f_fsid.val[0], 104174462Salfred fsb.f_fsid.val[1]); 10421558Srgrimes } else if (debug) 104337663Scharnier warnx("found ep fs=0x%x,0x%x", 10441558Srgrimes fsb.f_fsid.val[0], 10451558Srgrimes fsb.f_fsid.val[1]); 10461558Srgrimes } 10471558Srgrimes 10481558Srgrimes /* 10491558Srgrimes * Add dirpath to export mount point. 10501558Srgrimes */ 10511558Srgrimes dirp = add_expdir(&dirhead, cp, len); 10521558Srgrimes dirplen = len; 10531558Srgrimes } else { 10541558Srgrimes getexp_err(ep, tgrp); 10551558Srgrimes goto nextline; 10561558Srgrimes } 10571558Srgrimes *endcp = savedc; 10581558Srgrimes } else { 10591558Srgrimes savedc = *endcp; 10601558Srgrimes *endcp = '\0'; 10611558Srgrimes got_nondir = 1; 10621558Srgrimes if (ep == (struct exportlist *)NULL) { 10631558Srgrimes getexp_err(ep, tgrp); 10641558Srgrimes goto nextline; 10651558Srgrimes } 10661558Srgrimes 10671558Srgrimes /* 10681558Srgrimes * Get the host or netgroup. 10691558Srgrimes */ 10701558Srgrimes setnetgrent(cp); 10711558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 10721558Srgrimes do { 10731558Srgrimes if (has_host) { 10741558Srgrimes grp->gr_next = get_grp(); 10751558Srgrimes grp = grp->gr_next; 10761558Srgrimes } 10771558Srgrimes if (netgrp) { 107837003Sjoerg if (hst == 0) { 107937663Scharnier syslog(LOG_ERR, 108037663Scharnier "null hostname in netgroup %s, skipping", cp); 108137004Sjoerg grp->gr_type = GT_IGNORE; 108237003Sjoerg } else if (get_host(hst, grp, tgrp)) { 108337663Scharnier syslog(LOG_ERR, 108437663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 108529317Sjlemon grp->gr_type = GT_IGNORE; 10861558Srgrimes } 10877401Swpaul } else if (get_host(cp, grp, tgrp)) { 108837663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 108929317Sjlemon grp->gr_type = GT_IGNORE; 10901558Srgrimes } 10911558Srgrimes has_host = TRUE; 10921558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 10931558Srgrimes endnetgrent(); 10941558Srgrimes *endcp = savedc; 10951558Srgrimes } 10961558Srgrimes cp = endcp; 10971558Srgrimes nextfield(&cp, &endcp); 10981558Srgrimes len = endcp - cp; 10991558Srgrimes } 11001558Srgrimes if (check_options(dirhead)) { 11011558Srgrimes getexp_err(ep, tgrp); 11021558Srgrimes goto nextline; 11031558Srgrimes } 11041558Srgrimes if (!has_host) { 110575641Siedowse grp->gr_type = GT_DEFAULT; 11061558Srgrimes if (debug) 110737663Scharnier warnx("adding a default entry"); 11081558Srgrimes 11091558Srgrimes /* 11101558Srgrimes * Don't allow a network export coincide with a list of 11111558Srgrimes * host(s) on the same line. 11121558Srgrimes */ 11131558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 111475801Siedowse syslog(LOG_ERR, "network/host conflict"); 11151558Srgrimes getexp_err(ep, tgrp); 11161558Srgrimes goto nextline; 111729317Sjlemon 111874462Salfred /* 111974462Salfred * If an export list was specified on this line, make sure 112029317Sjlemon * that we have at least one valid entry, otherwise skip it. 112129317Sjlemon */ 112229317Sjlemon } else { 112329317Sjlemon grp = tgrp; 112474462Salfred while (grp && grp->gr_type == GT_IGNORE) 112529317Sjlemon grp = grp->gr_next; 112629317Sjlemon if (! grp) { 112729317Sjlemon getexp_err(ep, tgrp); 112829317Sjlemon goto nextline; 112929317Sjlemon } 11301558Srgrimes } 11311558Srgrimes 11321558Srgrimes /* 11331558Srgrimes * Loop through hosts, pushing the exports into the kernel. 11341558Srgrimes * After loop, tgrp points to the start of the list and 11351558Srgrimes * grp points to the last entry in the list. 11361558Srgrimes */ 11371558Srgrimes grp = tgrp; 11381558Srgrimes do { 113975635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 114075635Siedowse &fsb)) { 114175635Siedowse getexp_err(ep, tgrp); 114275635Siedowse goto nextline; 114375635Siedowse } 11441558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 11451558Srgrimes 11461558Srgrimes /* 11471558Srgrimes * Success. Update the data structures. 11481558Srgrimes */ 11491558Srgrimes if (has_host) { 11509336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 11511558Srgrimes grp->gr_next = grphead; 11521558Srgrimes grphead = tgrp; 11531558Srgrimes } else { 11541558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 11559336Sdfr opt_flags); 11561558Srgrimes free_grp(grp); 11571558Srgrimes } 11581558Srgrimes dirhead = (struct dirlist *)NULL; 11591558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 11601558Srgrimes ep2 = exphead; 11611558Srgrimes epp = &exphead; 11621558Srgrimes 11631558Srgrimes /* 11641558Srgrimes * Insert in the list in alphabetical order. 11651558Srgrimes */ 11661558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 11671558Srgrimes epp = &ep2->ex_next; 11681558Srgrimes ep2 = ep2->ex_next; 11691558Srgrimes } 11701558Srgrimes if (ep2) 11711558Srgrimes ep->ex_next = ep2; 11721558Srgrimes *epp = ep; 11731558Srgrimes ep->ex_flag |= EX_LINKED; 11741558Srgrimes } 11751558Srgrimesnextline: 11761558Srgrimes if (dirhead) { 11771558Srgrimes free_dir(dirhead); 11781558Srgrimes dirhead = (struct dirlist *)NULL; 11791558Srgrimes } 11801558Srgrimes } 11811558Srgrimes fclose(exp_file); 11821558Srgrimes} 11831558Srgrimes 11841558Srgrimes/* 11851558Srgrimes * Allocate an export list element 11861558Srgrimes */ 11871558Srgrimesstruct exportlist * 11881558Srgrimesget_exp() 11891558Srgrimes{ 11901558Srgrimes struct exportlist *ep; 11911558Srgrimes 11921558Srgrimes ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 11931558Srgrimes if (ep == (struct exportlist *)NULL) 11941558Srgrimes out_of_mem(); 119523681Speter memset(ep, 0, sizeof(struct exportlist)); 11961558Srgrimes return (ep); 11971558Srgrimes} 11981558Srgrimes 11991558Srgrimes/* 12001558Srgrimes * Allocate a group list element 12011558Srgrimes */ 12021558Srgrimesstruct grouplist * 12031558Srgrimesget_grp() 12041558Srgrimes{ 12051558Srgrimes struct grouplist *gp; 12061558Srgrimes 12071558Srgrimes gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 12081558Srgrimes if (gp == (struct grouplist *)NULL) 12091558Srgrimes out_of_mem(); 121023681Speter memset(gp, 0, sizeof(struct grouplist)); 12111558Srgrimes return (gp); 12121558Srgrimes} 12131558Srgrimes 12141558Srgrimes/* 12151558Srgrimes * Clean up upon an error in get_exportlist(). 12161558Srgrimes */ 12171558Srgrimesvoid 12181558Srgrimesgetexp_err(ep, grp) 12191558Srgrimes struct exportlist *ep; 12201558Srgrimes struct grouplist *grp; 12211558Srgrimes{ 12221558Srgrimes struct grouplist *tgrp; 12231558Srgrimes 122437663Scharnier syslog(LOG_ERR, "bad exports list line %s", line); 12251558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 12261558Srgrimes free_exp(ep); 12271558Srgrimes while (grp) { 12281558Srgrimes tgrp = grp; 12291558Srgrimes grp = grp->gr_next; 12301558Srgrimes free_grp(tgrp); 12311558Srgrimes } 12321558Srgrimes} 12331558Srgrimes 12341558Srgrimes/* 12351558Srgrimes * Search the export list for a matching fs. 12361558Srgrimes */ 12371558Srgrimesstruct exportlist * 12381558Srgrimesex_search(fsid) 12391558Srgrimes fsid_t *fsid; 12401558Srgrimes{ 12411558Srgrimes struct exportlist *ep; 12421558Srgrimes 12431558Srgrimes ep = exphead; 12441558Srgrimes while (ep) { 12451558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 12461558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 12471558Srgrimes return (ep); 12481558Srgrimes ep = ep->ex_next; 12491558Srgrimes } 12501558Srgrimes return (ep); 12511558Srgrimes} 12521558Srgrimes 12531558Srgrimes/* 12541558Srgrimes * Add a directory path to the list. 12551558Srgrimes */ 12561558Srgrimeschar * 12571558Srgrimesadd_expdir(dpp, cp, len) 12581558Srgrimes struct dirlist **dpp; 12591558Srgrimes char *cp; 12601558Srgrimes int len; 12611558Srgrimes{ 12621558Srgrimes struct dirlist *dp; 12631558Srgrimes 12641558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 126537663Scharnier if (dp == (struct dirlist *)NULL) 126637663Scharnier out_of_mem(); 12671558Srgrimes dp->dp_left = *dpp; 12681558Srgrimes dp->dp_right = (struct dirlist *)NULL; 12691558Srgrimes dp->dp_flag = 0; 12701558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 12711558Srgrimes strcpy(dp->dp_dirp, cp); 12721558Srgrimes *dpp = dp; 12731558Srgrimes return (dp->dp_dirp); 12741558Srgrimes} 12751558Srgrimes 12761558Srgrimes/* 12771558Srgrimes * Hang the dir list element off the dirpath binary tree as required 12781558Srgrimes * and update the entry for host. 12791558Srgrimes */ 12801558Srgrimesvoid 12819336Sdfrhang_dirp(dp, grp, ep, flags) 12821558Srgrimes struct dirlist *dp; 12831558Srgrimes struct grouplist *grp; 12841558Srgrimes struct exportlist *ep; 12859336Sdfr int flags; 12861558Srgrimes{ 12871558Srgrimes struct hostlist *hp; 12881558Srgrimes struct dirlist *dp2; 12891558Srgrimes 12909336Sdfr if (flags & OP_ALLDIRS) { 12911558Srgrimes if (ep->ex_defdir) 12921558Srgrimes free((caddr_t)dp); 12931558Srgrimes else 12941558Srgrimes ep->ex_defdir = dp; 12959336Sdfr if (grp == (struct grouplist *)NULL) { 12961558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 12979336Sdfr } else while (grp) { 12981558Srgrimes hp = get_ht(); 12991558Srgrimes hp->ht_grp = grp; 13001558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 13011558Srgrimes ep->ex_defdir->dp_hosts = hp; 13021558Srgrimes grp = grp->gr_next; 13031558Srgrimes } 13041558Srgrimes } else { 13051558Srgrimes 13061558Srgrimes /* 130737663Scharnier * Loop through the directories adding them to the tree. 13081558Srgrimes */ 13091558Srgrimes while (dp) { 13101558Srgrimes dp2 = dp->dp_left; 13119336Sdfr add_dlist(&ep->ex_dirl, dp, grp, flags); 13121558Srgrimes dp = dp2; 13131558Srgrimes } 13141558Srgrimes } 13151558Srgrimes} 13161558Srgrimes 13171558Srgrimes/* 13181558Srgrimes * Traverse the binary tree either updating a node that is already there 13191558Srgrimes * for the new directory or adding the new node. 13201558Srgrimes */ 13211558Srgrimesvoid 13229336Sdfradd_dlist(dpp, newdp, grp, flags) 13231558Srgrimes struct dirlist **dpp; 13241558Srgrimes struct dirlist *newdp; 13251558Srgrimes struct grouplist *grp; 13269336Sdfr int flags; 13271558Srgrimes{ 13281558Srgrimes struct dirlist *dp; 13291558Srgrimes struct hostlist *hp; 13301558Srgrimes int cmp; 13311558Srgrimes 13321558Srgrimes dp = *dpp; 13331558Srgrimes if (dp) { 13341558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 13351558Srgrimes if (cmp > 0) { 13369336Sdfr add_dlist(&dp->dp_left, newdp, grp, flags); 13371558Srgrimes return; 13381558Srgrimes } else if (cmp < 0) { 13399336Sdfr add_dlist(&dp->dp_right, newdp, grp, flags); 13401558Srgrimes return; 13411558Srgrimes } else 13421558Srgrimes free((caddr_t)newdp); 13431558Srgrimes } else { 13441558Srgrimes dp = newdp; 13451558Srgrimes dp->dp_left = (struct dirlist *)NULL; 13461558Srgrimes *dpp = dp; 13471558Srgrimes } 13481558Srgrimes if (grp) { 13491558Srgrimes 13501558Srgrimes /* 13511558Srgrimes * Hang all of the host(s) off of the directory point. 13521558Srgrimes */ 13531558Srgrimes do { 13541558Srgrimes hp = get_ht(); 13551558Srgrimes hp->ht_grp = grp; 13561558Srgrimes hp->ht_next = dp->dp_hosts; 13571558Srgrimes dp->dp_hosts = hp; 13581558Srgrimes grp = grp->gr_next; 13591558Srgrimes } while (grp); 13609336Sdfr } else { 13611558Srgrimes dp->dp_flag |= DP_DEFSET; 13629336Sdfr } 13631558Srgrimes} 13641558Srgrimes 13651558Srgrimes/* 13661558Srgrimes * Search for a dirpath on the export point. 13671558Srgrimes */ 13681558Srgrimesstruct dirlist * 136974462Salfreddirp_search(dp, dirp) 13701558Srgrimes struct dirlist *dp; 137174462Salfred char *dirp; 13721558Srgrimes{ 13731558Srgrimes int cmp; 13741558Srgrimes 13751558Srgrimes if (dp) { 137674462Salfred cmp = strcmp(dp->dp_dirp, dirp); 13771558Srgrimes if (cmp > 0) 137874462Salfred return (dirp_search(dp->dp_left, dirp)); 13791558Srgrimes else if (cmp < 0) 138074462Salfred return (dirp_search(dp->dp_right, dirp)); 13811558Srgrimes else 13821558Srgrimes return (dp); 13831558Srgrimes } 13841558Srgrimes return (dp); 13851558Srgrimes} 13861558Srgrimes 13871558Srgrimes/* 13881558Srgrimes * Scan for a host match in a directory tree. 13891558Srgrimes */ 13901558Srgrimesint 13919336Sdfrchk_host(dp, saddr, defsetp, hostsetp) 13921558Srgrimes struct dirlist *dp; 139374462Salfred struct sockaddr *saddr; 13941558Srgrimes int *defsetp; 13959336Sdfr int *hostsetp; 13961558Srgrimes{ 13971558Srgrimes struct hostlist *hp; 13981558Srgrimes struct grouplist *grp; 139974462Salfred struct addrinfo *ai; 14001558Srgrimes 14011558Srgrimes if (dp) { 14021558Srgrimes if (dp->dp_flag & DP_DEFSET) 14039336Sdfr *defsetp = dp->dp_flag; 14041558Srgrimes hp = dp->dp_hosts; 14051558Srgrimes while (hp) { 14061558Srgrimes grp = hp->ht_grp; 14071558Srgrimes switch (grp->gr_type) { 14081558Srgrimes case GT_HOST: 140974462Salfred ai = grp->gr_ptr.gt_addrinfo; 141074462Salfred for (; ai; ai = ai->ai_next) { 141175801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 141274462Salfred *hostsetp = 141374462Salfred (hp->ht_flag | DP_HOSTSET); 141474462Salfred return (1); 141574462Salfred } 14169336Sdfr } 141775801Siedowse break; 14181558Srgrimes case GT_NET: 141975801Siedowse if (!sacmp(saddr, (struct sockaddr *) 142075801Siedowse &grp->gr_ptr.gt_net.nt_net, 142175801Siedowse (struct sockaddr *) 142275801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 142374462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 142474462Salfred return (1); 142574462Salfred } 142675801Siedowse break; 142775801Siedowse } 14281558Srgrimes hp = hp->ht_next; 14291558Srgrimes } 14301558Srgrimes } 14311558Srgrimes return (0); 14321558Srgrimes} 14331558Srgrimes 14341558Srgrimes/* 14351558Srgrimes * Scan tree for a host that matches the address. 14361558Srgrimes */ 14371558Srgrimesint 14381558Srgrimesscan_tree(dp, saddr) 14391558Srgrimes struct dirlist *dp; 144074462Salfred struct sockaddr *saddr; 14411558Srgrimes{ 14429336Sdfr int defset, hostset; 14431558Srgrimes 14441558Srgrimes if (dp) { 14451558Srgrimes if (scan_tree(dp->dp_left, saddr)) 14461558Srgrimes return (1); 14479336Sdfr if (chk_host(dp, saddr, &defset, &hostset)) 14481558Srgrimes return (1); 14491558Srgrimes if (scan_tree(dp->dp_right, saddr)) 14501558Srgrimes return (1); 14511558Srgrimes } 14521558Srgrimes return (0); 14531558Srgrimes} 14541558Srgrimes 14551558Srgrimes/* 14561558Srgrimes * Traverse the dirlist tree and free it up. 14571558Srgrimes */ 14581558Srgrimesvoid 14591558Srgrimesfree_dir(dp) 14601558Srgrimes struct dirlist *dp; 14611558Srgrimes{ 14621558Srgrimes 14631558Srgrimes if (dp) { 14641558Srgrimes free_dir(dp->dp_left); 14651558Srgrimes free_dir(dp->dp_right); 14661558Srgrimes free_host(dp->dp_hosts); 14671558Srgrimes free((caddr_t)dp); 14681558Srgrimes } 14691558Srgrimes} 14701558Srgrimes 14711558Srgrimes/* 14721558Srgrimes * Parse the option string and update fields. 14731558Srgrimes * Option arguments may either be -<option>=<value> or 14741558Srgrimes * -<option> <value> 14751558Srgrimes */ 14761558Srgrimesint 14771558Srgrimesdo_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 14781558Srgrimes char **cpp, **endcpp; 14791558Srgrimes struct exportlist *ep; 14801558Srgrimes struct grouplist *grp; 14811558Srgrimes int *has_hostp; 14821558Srgrimes int *exflagsp; 148372650Sgreen struct xucred *cr; 14841558Srgrimes{ 14851558Srgrimes char *cpoptarg, *cpoptend; 14861558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 14871558Srgrimes int allflag, usedarg; 14881558Srgrimes 148951968Salfred savedc2 = '\0'; 14901558Srgrimes cpopt = *cpp; 14911558Srgrimes cpopt++; 14921558Srgrimes cp = *endcpp; 14931558Srgrimes savedc = *cp; 14941558Srgrimes *cp = '\0'; 14951558Srgrimes while (cpopt && *cpopt) { 14961558Srgrimes allflag = 1; 14971558Srgrimes usedarg = -2; 149837663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 14991558Srgrimes *cpoptend++ = '\0'; 150037663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 15011558Srgrimes *cpoptarg++ = '\0'; 15021558Srgrimes } else { 150337663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 15041558Srgrimes *cpoptarg++ = '\0'; 15051558Srgrimes else { 15061558Srgrimes *cp = savedc; 15071558Srgrimes nextfield(&cp, &endcp); 15081558Srgrimes **endcpp = '\0'; 15091558Srgrimes if (endcp > cp && *cp != '-') { 15101558Srgrimes cpoptarg = cp; 15111558Srgrimes savedc2 = *endcp; 15121558Srgrimes *endcp = '\0'; 15131558Srgrimes usedarg = 0; 15141558Srgrimes } 15151558Srgrimes } 15161558Srgrimes } 15171558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 15181558Srgrimes *exflagsp |= MNT_EXRDONLY; 15191558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 15201558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 15211558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 15221558Srgrimes usedarg++; 15231558Srgrimes parsecred(cpoptarg, cr); 15241558Srgrimes if (allflag == 0) { 15251558Srgrimes *exflagsp |= MNT_EXPORTANON; 15261558Srgrimes opt_flags |= OP_MAPALL; 15271558Srgrimes } else 15281558Srgrimes opt_flags |= OP_MAPROOT; 15291558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 153075801Siedowse !strcmp(cpopt, "m"))) { 15311558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 153237663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 15331558Srgrimes return (1); 15341558Srgrimes } 15351558Srgrimes usedarg++; 15361558Srgrimes opt_flags |= OP_MASK; 15371558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 15381558Srgrimes !strcmp(cpopt, "n"))) { 153974462Salfred if (strchr(cpoptarg, '/') != NULL) { 154074462Salfred if (debug) 154174462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 154274462Salfred opt_flags |= OP_MASKLEN; 154374462Salfred } 15441558Srgrimes if (grp->gr_type != GT_NULL) { 154537663Scharnier syslog(LOG_ERR, "network/host conflict"); 15461558Srgrimes return (1); 15471558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 154837663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 15491558Srgrimes return (1); 15501558Srgrimes } 15511558Srgrimes grp->gr_type = GT_NET; 15521558Srgrimes *has_hostp = 1; 15531558Srgrimes usedarg++; 15541558Srgrimes opt_flags |= OP_NET; 15551558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 15561558Srgrimes opt_flags |= OP_ALLDIRS; 155727447Sdfr } else if (!strcmp(cpopt, "public")) { 155827447Sdfr *exflagsp |= MNT_EXPUBLIC; 155927447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 156027447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 156127447Sdfr opt_flags |= OP_MAPALL; 156227447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 156327447Sdfr ep->ex_indexfile = strdup(cpoptarg); 15641558Srgrimes } else { 156537663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 15661558Srgrimes return (1); 15671558Srgrimes } 15681558Srgrimes if (usedarg >= 0) { 15691558Srgrimes *endcp = savedc2; 15701558Srgrimes **endcpp = savedc; 15711558Srgrimes if (usedarg > 0) { 15721558Srgrimes *cpp = cp; 15731558Srgrimes *endcpp = endcp; 15741558Srgrimes } 15751558Srgrimes return (0); 15761558Srgrimes } 15771558Srgrimes cpopt = cpoptend; 15781558Srgrimes } 15791558Srgrimes **endcpp = savedc; 15801558Srgrimes return (0); 15811558Srgrimes} 15821558Srgrimes 15831558Srgrimes/* 15841558Srgrimes * Translate a character string to the corresponding list of network 15851558Srgrimes * addresses for a hostname. 15861558Srgrimes */ 15871558Srgrimesint 15887401Swpaulget_host(cp, grp, tgrp) 15891558Srgrimes char *cp; 15901558Srgrimes struct grouplist *grp; 15917401Swpaul struct grouplist *tgrp; 15921558Srgrimes{ 15937401Swpaul struct grouplist *checkgrp; 159475635Siedowse struct addrinfo *ai, *tai, hints; 159574462Salfred int ecode; 159674462Salfred char host[NI_MAXHOST]; 15971558Srgrimes 159874462Salfred if (grp->gr_type != GT_NULL) { 159974462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 16001558Srgrimes return (1); 16011558Srgrimes } 160274462Salfred memset(&hints, 0, sizeof hints); 160374462Salfred hints.ai_flags = AI_CANONNAME; 160474462Salfred hints.ai_protocol = IPPROTO_UDP; 160574462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 160674462Salfred if (ecode != 0) { 160775635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 160874462Salfred return 1; 160974462Salfred } 161074462Salfred grp->gr_ptr.gt_addrinfo = ai; 161174462Salfred while (ai != NULL) { 161274462Salfred if (ai->ai_canonname == NULL) { 161374462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 161474462Salfred sizeof host, NULL, 0, ninumeric) != 0) 161574462Salfred strlcpy(host, "?", sizeof(host)); 161674462Salfred ai->ai_canonname = strdup(host); 161774462Salfred ai->ai_flags |= AI_CANONNAME; 161875641Siedowse } 161974462Salfred if (debug) 162075635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 162175635Siedowse /* 162275635Siedowse * Sanity check: make sure we don't already have an entry 162375635Siedowse * for this host in the grouplist. 162475635Siedowse */ 162575635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 162675635Siedowse checkgrp = checkgrp->gr_next) { 162775635Siedowse if (checkgrp->gr_type != GT_HOST) 162875635Siedowse continue; 162975635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 163075635Siedowse tai = tai->ai_next) { 163175801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 163275635Siedowse continue; 163375635Siedowse if (debug) 163475635Siedowse fprintf(stderr, 163575635Siedowse "ignoring duplicate host %s\n", 163675635Siedowse ai->ai_canonname); 163775635Siedowse grp->gr_type = GT_IGNORE; 163875635Siedowse return (0); 163975635Siedowse } 164075635Siedowse } 164174462Salfred ai = ai->ai_next; 16421558Srgrimes } 164375635Siedowse grp->gr_type = GT_HOST; 16441558Srgrimes return (0); 16451558Srgrimes} 16461558Srgrimes 16471558Srgrimes/* 16481558Srgrimes * Free up an exports list component 16491558Srgrimes */ 16501558Srgrimesvoid 16511558Srgrimesfree_exp(ep) 16521558Srgrimes struct exportlist *ep; 16531558Srgrimes{ 16541558Srgrimes 16551558Srgrimes if (ep->ex_defdir) { 16561558Srgrimes free_host(ep->ex_defdir->dp_hosts); 16571558Srgrimes free((caddr_t)ep->ex_defdir); 16581558Srgrimes } 16591558Srgrimes if (ep->ex_fsdir) 16601558Srgrimes free(ep->ex_fsdir); 166127447Sdfr if (ep->ex_indexfile) 166227447Sdfr free(ep->ex_indexfile); 16631558Srgrimes free_dir(ep->ex_dirl); 16641558Srgrimes free((caddr_t)ep); 16651558Srgrimes} 16661558Srgrimes 16671558Srgrimes/* 16681558Srgrimes * Free hosts. 16691558Srgrimes */ 16701558Srgrimesvoid 16711558Srgrimesfree_host(hp) 16721558Srgrimes struct hostlist *hp; 16731558Srgrimes{ 16741558Srgrimes struct hostlist *hp2; 16751558Srgrimes 16761558Srgrimes while (hp) { 16771558Srgrimes hp2 = hp; 16781558Srgrimes hp = hp->ht_next; 16791558Srgrimes free((caddr_t)hp2); 16801558Srgrimes } 16811558Srgrimes} 16821558Srgrimes 16831558Srgrimesstruct hostlist * 16841558Srgrimesget_ht() 16851558Srgrimes{ 16861558Srgrimes struct hostlist *hp; 16871558Srgrimes 16881558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 16891558Srgrimes if (hp == (struct hostlist *)NULL) 16901558Srgrimes out_of_mem(); 16911558Srgrimes hp->ht_next = (struct hostlist *)NULL; 16929336Sdfr hp->ht_flag = 0; 16931558Srgrimes return (hp); 16941558Srgrimes} 16951558Srgrimes 16961558Srgrimes/* 16971558Srgrimes * Out of memory, fatal 16981558Srgrimes */ 16991558Srgrimesvoid 17001558Srgrimesout_of_mem() 17011558Srgrimes{ 17021558Srgrimes 170337663Scharnier syslog(LOG_ERR, "out of memory"); 17041558Srgrimes exit(2); 17051558Srgrimes} 17061558Srgrimes 17071558Srgrimes/* 17081558Srgrimes * Do the mount syscall with the update flag to push the export info into 17091558Srgrimes * the kernel. 17101558Srgrimes */ 17111558Srgrimesint 17121558Srgrimesdo_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 17131558Srgrimes struct exportlist *ep; 17141558Srgrimes struct grouplist *grp; 17151558Srgrimes int exflags; 171672650Sgreen struct xucred *anoncrp; 17171558Srgrimes char *dirp; 17181558Srgrimes int dirplen; 17191558Srgrimes struct statfs *fsb; 17201558Srgrimes{ 172175841Siedowse struct statfs fsb1; 172274462Salfred struct addrinfo *ai; 172375801Siedowse struct export_args *eap; 172474462Salfred char *cp = NULL; 17251558Srgrimes int done; 17261558Srgrimes char savedc = '\0'; 17271558Srgrimes union { 17281558Srgrimes struct ufs_args ua; 17291558Srgrimes struct iso_args ia; 17309336Sdfr struct msdosfs_args da; 173154093Ssemenu struct ntfs_args na; 17321558Srgrimes } args; 17331558Srgrimes 173475801Siedowse bzero(&args, sizeof args); 173575801Siedowse /* XXX, we assume that all xx_args look like ufs_args. */ 17361558Srgrimes args.ua.fspec = 0; 173775801Siedowse eap = &args.ua.export; 173875801Siedowse 173975801Siedowse eap->ex_flags = exflags; 174075801Siedowse eap->ex_anon = *anoncrp; 174175801Siedowse eap->ex_indexfile = ep->ex_indexfile; 174275641Siedowse if (grp->gr_type == GT_HOST) 174374462Salfred ai = grp->gr_ptr.gt_addrinfo; 174475641Siedowse else 174575641Siedowse ai = NULL; 17461558Srgrimes done = FALSE; 17471558Srgrimes while (!done) { 17481558Srgrimes switch (grp->gr_type) { 17491558Srgrimes case GT_HOST: 175075641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 175174462Salfred goto skip; 175275801Siedowse eap->ex_addr = ai->ai_addr; 175375801Siedowse eap->ex_addrlen = ai->ai_addrlen; 175475801Siedowse eap->ex_masklen = 0; 17551558Srgrimes break; 17561558Srgrimes case GT_NET: 175775801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 175874462Salfred have_v6 == 0) 175974462Salfred goto skip; 176075801Siedowse eap->ex_addr = 176175801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 176275801Siedowse eap->ex_addrlen = args.ua.export.ex_addr->sa_len; 176375801Siedowse eap->ex_mask = 176475801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 176575801Siedowse eap->ex_masklen = args.ua.export.ex_mask->sa_len; 17661558Srgrimes break; 176775641Siedowse case GT_DEFAULT: 176875801Siedowse eap->ex_addr = NULL; 176975801Siedowse eap->ex_addrlen = 0; 177075801Siedowse eap->ex_mask = NULL; 177175801Siedowse eap->ex_masklen = 0; 177275641Siedowse break; 17737401Swpaul case GT_IGNORE: 17747401Swpaul return(0); 17757401Swpaul break; 17761558Srgrimes default: 177737663Scharnier syslog(LOG_ERR, "bad grouptype"); 17781558Srgrimes if (cp) 17791558Srgrimes *cp = savedc; 17801558Srgrimes return (1); 17811558Srgrimes }; 17821558Srgrimes 17831558Srgrimes /* 17841558Srgrimes * XXX: 17851558Srgrimes * Maybe I should just use the fsb->f_mntonname path instead 17861558Srgrimes * of looping back up the dirp to the mount point?? 17871558Srgrimes * Also, needs to know how to export all types of local 178823681Speter * exportable file systems and not just "ufs". 17891558Srgrimes */ 17909336Sdfr while (mount(fsb->f_fstypename, dirp, 179174462Salfred fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 17921558Srgrimes if (cp) 17931558Srgrimes *cp-- = savedc; 17941558Srgrimes else 17951558Srgrimes cp = dirp + dirplen - 1; 17961558Srgrimes if (errno == EPERM) { 179775635Siedowse if (debug) 179875635Siedowse warnx("can't change attributes for %s", 179975635Siedowse dirp); 18001558Srgrimes syslog(LOG_ERR, 180137663Scharnier "can't change attributes for %s", dirp); 18021558Srgrimes return (1); 18031558Srgrimes } 18041558Srgrimes if (opt_flags & OP_ALLDIRS) { 180537663Scharnier syslog(LOG_ERR, "could not remount %s: %m", 18064895Swollman dirp); 18071558Srgrimes return (1); 18081558Srgrimes } 18091558Srgrimes /* back up over the last component */ 18101558Srgrimes while (*cp == '/' && cp > dirp) 18111558Srgrimes cp--; 18121558Srgrimes while (*(cp - 1) != '/' && cp > dirp) 18131558Srgrimes cp--; 18141558Srgrimes if (cp == dirp) { 18151558Srgrimes if (debug) 181637663Scharnier warnx("mnt unsucc"); 181737663Scharnier syslog(LOG_ERR, "can't export %s", dirp); 18181558Srgrimes return (1); 18191558Srgrimes } 18201558Srgrimes savedc = *cp; 18211558Srgrimes *cp = '\0'; 182275841Siedowse /* Check that we're still on the same filesystem. */ 182375841Siedowse if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid, 182475841Siedowse &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) { 182575841Siedowse *cp = savedc; 182675841Siedowse syslog(LOG_ERR, "can't export %s", dirp); 182775841Siedowse return (1); 182875841Siedowse } 18291558Srgrimes } 183074462Salfredskip: 183175641Siedowse if (ai != NULL) 183274462Salfred ai = ai->ai_next; 183375641Siedowse if (ai == NULL) 18341558Srgrimes done = TRUE; 18351558Srgrimes } 18361558Srgrimes if (cp) 18371558Srgrimes *cp = savedc; 18381558Srgrimes return (0); 18391558Srgrimes} 18401558Srgrimes 18411558Srgrimes/* 18421558Srgrimes * Translate a net address. 184375801Siedowse * 184475801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 18451558Srgrimes */ 18461558Srgrimesint 18471558Srgrimesget_net(cp, net, maskflg) 18481558Srgrimes char *cp; 18491558Srgrimes struct netmsk *net; 18501558Srgrimes int maskflg; 18511558Srgrimes{ 185275861Siedowse struct netent *np = NULL; 185374462Salfred char *name, *p, *prefp; 185475801Siedowse struct sockaddr_in sin; 185575861Siedowse struct sockaddr *sa = NULL; 185674462Salfred struct addrinfo hints, *ai = NULL; 185774462Salfred char netname[NI_MAXHOST]; 185874462Salfred long preflen; 18591558Srgrimes 186075635Siedowse p = prefp = NULL; 186174462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 186274462Salfred p = strchr(cp, '/'); 186374462Salfred *p = '\0'; 186474462Salfred prefp = p + 1; 186574462Salfred } 186674462Salfred 186775861Siedowse /* 186875861Siedowse * Check for a numeric address first. We wish to avoid 186975861Siedowse * possible DNS lookups in getnetbyname(). 187075861Siedowse */ 187175861Siedowse if (isxdigit(*cp) || *cp == ':') { 187274462Salfred memset(&hints, 0, sizeof hints); 187375801Siedowse /* Ensure the mask and the network have the same family. */ 187475801Siedowse if (maskflg && (opt_flags & OP_NET)) 187575801Siedowse hints.ai_family = net->nt_net.ss_family; 187675801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 187775801Siedowse hints.ai_family = net->nt_mask.ss_family; 187875801Siedowse else 187975801Siedowse hints.ai_family = AF_UNSPEC; 188074462Salfred hints.ai_flags = AI_NUMERICHOST; 188175861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 188275861Siedowse sa = ai->ai_addr; 188375861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 188474462Salfred /* 188575801Siedowse * The address in `cp' is really a network address, so 188675801Siedowse * use inet_network() to re-interpret this correctly. 188775801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 188874462Salfred */ 188975801Siedowse bzero(&sin, sizeof sin); 189074462Salfred sin.sin_family = AF_INET; 189174462Salfred sin.sin_len = sizeof sin; 189275801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 189374462Salfred if (debug) 189475801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 189575801Siedowse inet_ntoa(sin.sin_addr)); 189674462Salfred sa = (struct sockaddr *)&sin; 189775861Siedowse } 189875861Siedowse } 189975861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 190075861Siedowse bzero(&sin, sizeof sin); 190175861Siedowse sin.sin_family = AF_INET; 190275861Siedowse sin.sin_len = sizeof sin; 190375861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 190475861Siedowse sa = (struct sockaddr *)&sin; 190575861Siedowse } 190675861Siedowse if (sa == NULL) 190774462Salfred goto fail; 190825318Spst 190975801Siedowse if (maskflg) { 191075801Siedowse /* The specified sockaddr is a mask. */ 191175801Siedowse if (checkmask(sa) != 0) 191275801Siedowse goto fail; 191375801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 191475801Siedowse opt_flags |= OP_HAVEMASK; 191575801Siedowse } else { 191675801Siedowse /* The specified sockaddr is a network address. */ 191775801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 191874462Salfred 191975801Siedowse /* Get a network name for the export list. */ 192075801Siedowse if (np) { 192175801Siedowse name = np->n_name; 192275801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 192375801Siedowse NULL, 0, ninumeric) == 0) { 192475801Siedowse name = netname; 192575801Siedowse } else { 192675801Siedowse goto fail; 192775801Siedowse } 192875801Siedowse if ((net->nt_name = strdup(name)) == NULL) 192975801Siedowse out_of_mem(); 193075801Siedowse 193175801Siedowse /* 193275801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 193375801Siedowse * from the class of an IPv4 address. 193475801Siedowse */ 193574462Salfred if (opt_flags & OP_MASKLEN) { 193674462Salfred preflen = strtol(prefp, NULL, 10); 193775801Siedowse if (preflen < 0L || preflen == LONG_MAX) 193874462Salfred goto fail; 193975801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 194075801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 194175801Siedowse goto fail; 194275801Siedowse opt_flags |= OP_HAVEMASK; 194374462Salfred *p = '/'; 194475801Siedowse } else if (sa->sa_family == AF_INET && 194575801Siedowse (opt_flags & OP_MASK) == 0) { 194675801Siedowse in_addr_t addr; 194774462Salfred 194875801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 194975801Siedowse if (IN_CLASSA(addr)) 195075801Siedowse preflen = 8; 195175801Siedowse else if (IN_CLASSB(addr)) 195275801Siedowse preflen = 16; 195375801Siedowse else if (IN_CLASSC(addr)) 195475801Siedowse preflen = 24; 195575801Siedowse else if (IN_CLASSD(addr)) 195675801Siedowse preflen = 28; 195775801Siedowse else 195875801Siedowse preflen = 32; /* XXX */ 195975801Siedowse 196075801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 196175801Siedowse makemask(&net->nt_mask, (int)preflen); 196275801Siedowse opt_flags |= OP_HAVEMASK; 196374462Salfred } 196474462Salfred } 196574462Salfred 196674462Salfred if (ai) 196774462Salfred freeaddrinfo(ai); 196874462Salfred return 0; 196974462Salfred 197074462Salfredfail: 197174462Salfred if (ai) 197274462Salfred freeaddrinfo(ai); 197374462Salfred return 1; 19741558Srgrimes} 19751558Srgrimes 19761558Srgrimes/* 19771558Srgrimes * Parse out the next white space separated field 19781558Srgrimes */ 19791558Srgrimesvoid 19801558Srgrimesnextfield(cp, endcp) 19811558Srgrimes char **cp; 19821558Srgrimes char **endcp; 19831558Srgrimes{ 19841558Srgrimes char *p; 19851558Srgrimes 19861558Srgrimes p = *cp; 19871558Srgrimes while (*p == ' ' || *p == '\t') 19881558Srgrimes p++; 19891558Srgrimes if (*p == '\n' || *p == '\0') 19901558Srgrimes *cp = *endcp = p; 19911558Srgrimes else { 19921558Srgrimes *cp = p++; 19931558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 19941558Srgrimes p++; 19951558Srgrimes *endcp = p; 19961558Srgrimes } 19971558Srgrimes} 19981558Srgrimes 19991558Srgrimes/* 20001558Srgrimes * Get an exports file line. Skip over blank lines and handle line 20011558Srgrimes * continuations. 20021558Srgrimes */ 20031558Srgrimesint 20041558Srgrimesget_line() 20051558Srgrimes{ 20061558Srgrimes char *p, *cp; 20071558Srgrimes int len; 20081558Srgrimes int totlen, cont_line; 20091558Srgrimes 20101558Srgrimes /* 20111558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 20121558Srgrimes */ 20131558Srgrimes p = line; 20141558Srgrimes totlen = 0; 20151558Srgrimes do { 20161558Srgrimes if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 20171558Srgrimes return (0); 20181558Srgrimes len = strlen(p); 20191558Srgrimes cp = p + len - 1; 20201558Srgrimes cont_line = 0; 20211558Srgrimes while (cp >= p && 20221558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 20231558Srgrimes if (*cp == '\\') 20241558Srgrimes cont_line = 1; 20251558Srgrimes cp--; 20261558Srgrimes len--; 20271558Srgrimes } 202879117Sdd if (cont_line) { 202979117Sdd *++cp = ' '; 203079117Sdd len++; 203179117Sdd } 20321558Srgrimes *++cp = '\0'; 20331558Srgrimes if (len > 0) { 20341558Srgrimes totlen += len; 20351558Srgrimes if (totlen >= LINESIZ) { 203637663Scharnier syslog(LOG_ERR, "exports line too long"); 20371558Srgrimes exit(2); 20381558Srgrimes } 20391558Srgrimes p = cp; 20401558Srgrimes } 20411558Srgrimes } while (totlen == 0 || cont_line); 20421558Srgrimes return (1); 20431558Srgrimes} 20441558Srgrimes 20451558Srgrimes/* 20461558Srgrimes * Parse a description of a credential. 20471558Srgrimes */ 20481558Srgrimesvoid 20491558Srgrimesparsecred(namelist, cr) 20501558Srgrimes char *namelist; 205172650Sgreen struct xucred *cr; 20521558Srgrimes{ 20531558Srgrimes char *name; 20541558Srgrimes int cnt; 20551558Srgrimes char *names; 20561558Srgrimes struct passwd *pw; 20571558Srgrimes struct group *gr; 20581558Srgrimes int ngroups, groups[NGROUPS + 1]; 20591558Srgrimes 20601558Srgrimes /* 206137663Scharnier * Set up the unprivileged user. 20621558Srgrimes */ 20631558Srgrimes cr->cr_uid = -2; 20641558Srgrimes cr->cr_groups[0] = -2; 20651558Srgrimes cr->cr_ngroups = 1; 20661558Srgrimes /* 20671558Srgrimes * Get the user's password table entry. 20681558Srgrimes */ 20691558Srgrimes names = strsep(&namelist, " \t\n"); 20701558Srgrimes name = strsep(&names, ":"); 20711558Srgrimes if (isdigit(*name) || *name == '-') 20721558Srgrimes pw = getpwuid(atoi(name)); 20731558Srgrimes else 20741558Srgrimes pw = getpwnam(name); 20751558Srgrimes /* 20761558Srgrimes * Credentials specified as those of a user. 20771558Srgrimes */ 20781558Srgrimes if (names == NULL) { 20791558Srgrimes if (pw == NULL) { 208037663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 20811558Srgrimes return; 20821558Srgrimes } 20831558Srgrimes cr->cr_uid = pw->pw_uid; 20841558Srgrimes ngroups = NGROUPS + 1; 20851558Srgrimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 208637663Scharnier syslog(LOG_ERR, "too many groups"); 20871558Srgrimes /* 20881558Srgrimes * Convert from int's to gid_t's and compress out duplicate 20891558Srgrimes */ 20901558Srgrimes cr->cr_ngroups = ngroups - 1; 20911558Srgrimes cr->cr_groups[0] = groups[0]; 20921558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 20931558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 20941558Srgrimes return; 20951558Srgrimes } 20961558Srgrimes /* 20971558Srgrimes * Explicit credential specified as a colon separated list: 20981558Srgrimes * uid:gid:gid:... 20991558Srgrimes */ 21001558Srgrimes if (pw != NULL) 21011558Srgrimes cr->cr_uid = pw->pw_uid; 21021558Srgrimes else if (isdigit(*name) || *name == '-') 21031558Srgrimes cr->cr_uid = atoi(name); 21041558Srgrimes else { 210537663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 21061558Srgrimes return; 21071558Srgrimes } 21081558Srgrimes cr->cr_ngroups = 0; 21091558Srgrimes while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 21101558Srgrimes name = strsep(&names, ":"); 21111558Srgrimes if (isdigit(*name) || *name == '-') { 21121558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 21131558Srgrimes } else { 21141558Srgrimes if ((gr = getgrnam(name)) == NULL) { 211537663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 21161558Srgrimes continue; 21171558Srgrimes } 21181558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 21191558Srgrimes } 21201558Srgrimes } 21211558Srgrimes if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 212237663Scharnier syslog(LOG_ERR, "too many groups"); 21231558Srgrimes} 21241558Srgrimes 21251558Srgrimes#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 21261558Srgrimes/* 21271558Srgrimes * Routines that maintain the remote mounttab 21281558Srgrimes */ 21291558Srgrimesvoid 21301558Srgrimesget_mountlist() 21311558Srgrimes{ 21321558Srgrimes struct mountlist *mlp, **mlpp; 213323681Speter char *host, *dirp, *cp; 21341558Srgrimes char str[STRSIZ]; 21351558Srgrimes FILE *mlfile; 21361558Srgrimes 21371558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 213853117Sbillf if (errno == ENOENT) 213953117Sbillf return; 214053117Sbillf else { 214153117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 214253117Sbillf return; 214353117Sbillf } 21441558Srgrimes } 21451558Srgrimes mlpp = &mlhead; 21461558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 214723681Speter cp = str; 214823681Speter host = strsep(&cp, " \t\n"); 214923681Speter dirp = strsep(&cp, " \t\n"); 215023681Speter if (host == NULL || dirp == NULL) 21511558Srgrimes continue; 21521558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 215337663Scharnier if (mlp == (struct mountlist *)NULL) 215437663Scharnier out_of_mem(); 215523681Speter strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 215623681Speter mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 215723681Speter strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 215823681Speter mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 21591558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 21601558Srgrimes *mlpp = mlp; 21611558Srgrimes mlpp = &mlp->ml_next; 21621558Srgrimes } 21631558Srgrimes fclose(mlfile); 21641558Srgrimes} 21651558Srgrimes 216675635Siedowsevoid 216775635Siedowsedel_mlist(char *hostp, char *dirp) 21681558Srgrimes{ 21691558Srgrimes struct mountlist *mlp, **mlpp; 21701558Srgrimes struct mountlist *mlp2; 21711558Srgrimes FILE *mlfile; 21721558Srgrimes int fnd = 0; 21731558Srgrimes 21741558Srgrimes mlpp = &mlhead; 21751558Srgrimes mlp = mlhead; 21761558Srgrimes while (mlp) { 21771558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 21781558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 21791558Srgrimes fnd = 1; 21801558Srgrimes mlp2 = mlp; 21811558Srgrimes *mlpp = mlp = mlp->ml_next; 21821558Srgrimes free((caddr_t)mlp2); 21831558Srgrimes } else { 21841558Srgrimes mlpp = &mlp->ml_next; 21851558Srgrimes mlp = mlp->ml_next; 21861558Srgrimes } 21871558Srgrimes } 21881558Srgrimes if (fnd) { 21891558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 219037663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 21911558Srgrimes return; 21921558Srgrimes } 21931558Srgrimes mlp = mlhead; 21941558Srgrimes while (mlp) { 21951558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 21961558Srgrimes mlp = mlp->ml_next; 21971558Srgrimes } 21981558Srgrimes fclose(mlfile); 21991558Srgrimes } 22001558Srgrimes} 22011558Srgrimes 22021558Srgrimesvoid 22031558Srgrimesadd_mlist(hostp, dirp) 22041558Srgrimes char *hostp, *dirp; 22051558Srgrimes{ 22061558Srgrimes struct mountlist *mlp, **mlpp; 22071558Srgrimes FILE *mlfile; 22081558Srgrimes 22091558Srgrimes mlpp = &mlhead; 22101558Srgrimes mlp = mlhead; 22111558Srgrimes while (mlp) { 22121558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 22131558Srgrimes return; 22141558Srgrimes mlpp = &mlp->ml_next; 22151558Srgrimes mlp = mlp->ml_next; 22161558Srgrimes } 22171558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 221837663Scharnier if (mlp == (struct mountlist *)NULL) 221937663Scharnier out_of_mem(); 22201558Srgrimes strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 22211558Srgrimes mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 22221558Srgrimes strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 22231558Srgrimes mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 22241558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 22251558Srgrimes *mlpp = mlp; 22261558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 222737663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 22281558Srgrimes return; 22291558Srgrimes } 22301558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 22311558Srgrimes fclose(mlfile); 22321558Srgrimes} 22331558Srgrimes 22341558Srgrimes/* 22351558Srgrimes * Free up a group list. 22361558Srgrimes */ 22371558Srgrimesvoid 22381558Srgrimesfree_grp(grp) 22391558Srgrimes struct grouplist *grp; 22401558Srgrimes{ 22411558Srgrimes if (grp->gr_type == GT_HOST) { 224274462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 224374462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 22441558Srgrimes } else if (grp->gr_type == GT_NET) { 22451558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 22461558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 22471558Srgrimes } 22481558Srgrimes free((caddr_t)grp); 22491558Srgrimes} 22501558Srgrimes 22511558Srgrimes#ifdef DEBUG 22521558Srgrimesvoid 22531558SrgrimesSYSLOG(int pri, const char *fmt, ...) 22541558Srgrimes{ 22551558Srgrimes va_list ap; 22561558Srgrimes 22571558Srgrimes va_start(ap, fmt); 22581558Srgrimes vfprintf(stderr, fmt, ap); 22591558Srgrimes va_end(ap); 22601558Srgrimes} 22611558Srgrimes#endif /* DEBUG */ 22621558Srgrimes 22631558Srgrimes/* 22641558Srgrimes * Check options for consistency. 22651558Srgrimes */ 22661558Srgrimesint 22671558Srgrimescheck_options(dp) 22681558Srgrimes struct dirlist *dp; 22691558Srgrimes{ 22701558Srgrimes 22711558Srgrimes if (dp == (struct dirlist *)NULL) 22721558Srgrimes return (1); 227383653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 227483653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 22751558Srgrimes return (1); 22761558Srgrimes } 22771558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 227875801Siedowse syslog(LOG_ERR, "-mask requires -network"); 227975801Siedowse return (1); 22801558Srgrimes } 228175801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 228275801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 228375801Siedowse return (1); 228475801Siedowse } 228575801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 228675801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 228775801Siedowse return (1); 228875801Siedowse } 22891558Srgrimes if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 229045927Salex syslog(LOG_ERR, "-alldirs has multiple directories"); 22911558Srgrimes return (1); 22921558Srgrimes } 22931558Srgrimes return (0); 22941558Srgrimes} 22951558Srgrimes 22961558Srgrimes/* 22971558Srgrimes * Check an absolute directory path for any symbolic links. Return true 22981558Srgrimes */ 22991558Srgrimesint 23001558Srgrimescheck_dirpath(dirp) 23011558Srgrimes char *dirp; 23021558Srgrimes{ 23031558Srgrimes char *cp; 23041558Srgrimes int ret = 1; 23051558Srgrimes struct stat sb; 23061558Srgrimes 23071558Srgrimes cp = dirp + 1; 23081558Srgrimes while (*cp && ret) { 23091558Srgrimes if (*cp == '/') { 23101558Srgrimes *cp = '\0'; 23119336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 23121558Srgrimes ret = 0; 23131558Srgrimes *cp = '/'; 23141558Srgrimes } 23151558Srgrimes cp++; 23161558Srgrimes } 23179336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 23181558Srgrimes ret = 0; 23191558Srgrimes return (ret); 23201558Srgrimes} 23219336Sdfr 232275801Siedowse/* 232375801Siedowse * Make a netmask according to the specified prefix length. The ss_family 232475801Siedowse * and other non-address fields must be initialised before calling this. 232575801Siedowse */ 232675801Siedowseint 232775801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 232874462Salfred{ 232975801Siedowse u_char *p; 233075801Siedowse int bits, i, len; 233174462Salfred 233275801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 233375801Siedowse return (-1); 233475801Siedowse if (bitlen > len * NBBY) 233575801Siedowse return (-1); 233674462Salfred 233775801Siedowse for (i = 0; i < len; i++) { 233875801Siedowse bits = (bitlen > NBBY) ? NBBY : bitlen; 233975801Siedowse *p++ = (1 << bits) - 1; 234075801Siedowse bitlen -= bits; 234174462Salfred } 234275801Siedowse return 0; 234374462Salfred} 234474462Salfred 234575801Siedowse/* 234675801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 234775801Siedowse * is acceptable (i.e. of the form 1...10....0). 234875801Siedowse */ 234975801Siedowseint 235075801Siedowsecheckmask(struct sockaddr *sa) 235174462Salfred{ 235275801Siedowse u_char *mask; 235375801Siedowse int i, len; 235474462Salfred 235575801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 235675801Siedowse return (-1); 235775801Siedowse 235875801Siedowse for (i = 0; i < len; i++) 235975801Siedowse if (mask[i] != 0xff) 236075801Siedowse break; 236175801Siedowse if (i < len) { 236275801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 236375801Siedowse return (-1); 236475801Siedowse i++; 236574462Salfred } 236675801Siedowse for (; i < len; i++) 236775801Siedowse if (mask[i] != 0) 236875801Siedowse return (-1); 236975801Siedowse return (0); 237074462Salfred} 237174462Salfred 237275801Siedowse/* 237375801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 237475801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 237575801Siedowse * If samask is NULL, perform a full comparision. 237675801Siedowse */ 237775801Siedowseint 237875801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 237974462Salfred{ 238075801Siedowse unsigned char *p1, *p2, *mask; 238175801Siedowse int len, i; 238274462Salfred 238375801Siedowse if (sa1->sa_family != sa2->sa_family || 238475801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 238575801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 238675801Siedowse return (1); 238775801Siedowse 238875801Siedowse switch (sa1->sa_family) { 238974462Salfred case AF_INET6: 239075801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 239175801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 239275801Siedowse return (1); 239374462Salfred break; 239474462Salfred } 239574462Salfred 239675801Siedowse /* Simple binary comparison if no mask specified. */ 239775801Siedowse if (samask == NULL) 239875801Siedowse return (memcmp(p1, p2, len)); 239974462Salfred 240075801Siedowse /* Set up the mask, and do a mask-based comparison. */ 240175801Siedowse if (sa1->sa_family != samask->sa_family || 240275801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 240375801Siedowse return (1); 240474462Salfred 240575801Siedowse for (i = 0; i < len; i++) 240675801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 240775801Siedowse return (1); 240875801Siedowse return (0); 240974462Salfred} 241074462Salfred 241175801Siedowse/* 241275801Siedowse * Return a pointer to the part of the sockaddr that contains the 241375801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 241475801Siedowse * NULL if the address family is unknown. 241575801Siedowse */ 241675801Siedowsevoid * 241775801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 241875801Siedowse void *p; 241974462Salfred int len; 242074462Salfred 242175801Siedowse switch (sa->sa_family) { 242274462Salfred case AF_INET: 242375801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 242475801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 242574462Salfred break; 242674462Salfred case AF_INET6: 242775801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 242875801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 242974462Salfred break; 243074462Salfred default: 243175801Siedowse p = NULL; 243275801Siedowse len = 0; 243374462Salfred } 243474462Salfred 243575801Siedowse if (nbytes != NULL) 243675801Siedowse *nbytes = len; 243775801Siedowse return (p); 243874462Salfred} 243974462Salfred 244075754Siedowsevoid 244175754Siedowsehuphandler(int sig) 244275754Siedowse{ 244375754Siedowse got_sighup = 1; 244475754Siedowse} 244575754Siedowse 244674462Salfredvoid terminate(sig) 244774462Salfredint sig; 244874462Salfred{ 244974462Salfred close(mountdlockfd); 245074462Salfred unlink(MOUNTDLOCK); 245174792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 245274792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 245374462Salfred exit (0); 245474462Salfred} 2455