mountd.c revision 126572
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 43105267Scharnier#if 0 441558Srgrimes#ifndef lint 4537663Scharnierstatic char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 46105267Scharnier#endif /*not lint*/ 4737663Scharnier#endif 481558Srgrimes 49105267Scharnier#include <sys/cdefs.h> 50105267Scharnier__FBSDID("$FreeBSD: head/usr.sbin/mountd/mountd.c 126572 2004-03-04 04:42:52Z bms $"); 51105267Scharnier 521558Srgrimes#include <sys/param.h> 531558Srgrimes#include <sys/mount.h> 5474462Salfred#include <sys/fcntl.h> 551558Srgrimes#include <sys/stat.h> 561558Srgrimes#include <sys/syslog.h> 5724330Sguido#include <sys/sysctl.h> 5896622Siedowse#include <sys/linker.h> 5996622Siedowse#include <sys/module.h> 601558Srgrimes 611558Srgrimes#include <rpc/rpc.h> 62109363Smbr#include <rpc/rpc_com.h> 631558Srgrimes#include <rpc/pmap_clnt.h> 6474462Salfred#include <rpc/pmap_prot.h> 6574462Salfred#include <rpcsvc/mount.h> 661558Srgrimes#include <nfs/rpcv2.h> 679336Sdfr#include <nfs/nfsproto.h> 6883653Speter#include <nfsserver/nfs.h> 6923681Speter#include <ufs/ufs/ufsmount.h> 7077162Sru#include <fs/msdosfs/msdosfsmount.h> 7177223Sru#include <fs/ntfs/ntfsmount.h> 7223681Speter#include <isofs/cd9660/cd9660_mount.h> /* XXX need isofs in include */ 731558Srgrimes 741558Srgrimes#include <arpa/inet.h> 751558Srgrimes 761558Srgrimes#include <ctype.h> 7737663Scharnier#include <err.h> 781558Srgrimes#include <errno.h> 791558Srgrimes#include <grp.h> 80103949Smike#include <limits.h> 811558Srgrimes#include <netdb.h> 821558Srgrimes#include <pwd.h> 831558Srgrimes#include <signal.h> 841558Srgrimes#include <stdio.h> 851558Srgrimes#include <stdlib.h> 861558Srgrimes#include <string.h> 871558Srgrimes#include <unistd.h> 881558Srgrimes#include "pathnames.h" 891558Srgrimes 901558Srgrimes#ifdef DEBUG 911558Srgrimes#include <stdarg.h> 921558Srgrimes#endif 931558Srgrimes 9474462Salfred#ifndef MOUNTDLOCK 9574462Salfred#define MOUNTDLOCK "/var/run/mountd.lock" 9674462Salfred#endif 9774462Salfred 981558Srgrimes/* 991558Srgrimes * Structures for keeping the mount list and export list 1001558Srgrimes */ 1011558Srgrimesstruct mountlist { 1021558Srgrimes struct mountlist *ml_next; 1031558Srgrimes char ml_host[RPCMNT_NAMELEN+1]; 1041558Srgrimes char ml_dirp[RPCMNT_PATHLEN+1]; 1051558Srgrimes}; 1061558Srgrimes 1071558Srgrimesstruct dirlist { 1081558Srgrimes struct dirlist *dp_left; 1091558Srgrimes struct dirlist *dp_right; 1101558Srgrimes int dp_flag; 1111558Srgrimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 1121558Srgrimes char dp_dirp[1]; /* Actually malloc'd to size of dir */ 1131558Srgrimes}; 1141558Srgrimes/* dp_flag bits */ 1151558Srgrimes#define DP_DEFSET 0x1 1169336Sdfr#define DP_HOSTSET 0x2 1171558Srgrimes 1181558Srgrimesstruct exportlist { 1191558Srgrimes struct exportlist *ex_next; 1201558Srgrimes struct dirlist *ex_dirl; 1211558Srgrimes struct dirlist *ex_defdir; 1221558Srgrimes int ex_flag; 1231558Srgrimes fsid_t ex_fs; 1241558Srgrimes char *ex_fsdir; 12527447Sdfr char *ex_indexfile; 1261558Srgrimes}; 1271558Srgrimes/* ex_flag bits */ 1281558Srgrimes#define EX_LINKED 0x1 1291558Srgrimes 1301558Srgrimesstruct netmsk { 13174462Salfred struct sockaddr_storage nt_net; 13275801Siedowse struct sockaddr_storage nt_mask; 13342144Sdfr char *nt_name; 1341558Srgrimes}; 1351558Srgrimes 1361558Srgrimesunion grouptypes { 13774462Salfred struct addrinfo *gt_addrinfo; 1381558Srgrimes struct netmsk gt_net; 1391558Srgrimes}; 1401558Srgrimes 1411558Srgrimesstruct grouplist { 1421558Srgrimes int gr_type; 1431558Srgrimes union grouptypes gr_ptr; 1441558Srgrimes struct grouplist *gr_next; 1451558Srgrimes}; 1461558Srgrimes/* Group types */ 1471558Srgrimes#define GT_NULL 0x0 1481558Srgrimes#define GT_HOST 0x1 1491558Srgrimes#define GT_NET 0x2 15075641Siedowse#define GT_DEFAULT 0x3 1517401Swpaul#define GT_IGNORE 0x5 1521558Srgrimes 1531558Srgrimesstruct hostlist { 1549336Sdfr int ht_flag; /* Uses DP_xx bits */ 1551558Srgrimes struct grouplist *ht_grp; 1561558Srgrimes struct hostlist *ht_next; 1571558Srgrimes}; 1581558Srgrimes 1599336Sdfrstruct fhreturn { 1609336Sdfr int fhr_flag; 1619336Sdfr int fhr_vers; 1629336Sdfr nfsfh_t fhr_fh; 1639336Sdfr}; 1649336Sdfr 1651558Srgrimes/* Global defs */ 16692882Simpchar *add_expdir(struct dirlist **, char *, int); 16792882Simpvoid add_dlist(struct dirlist **, struct dirlist *, 16892882Simp struct grouplist *, int); 16992882Simpvoid add_mlist(char *, char *); 17092882Simpint check_dirpath(char *); 17192882Simpint check_options(struct dirlist *); 17275801Siedowseint checkmask(struct sockaddr *sa); 17392882Simpint chk_host(struct dirlist *, struct sockaddr *, int *, int *); 17475635Siedowsevoid del_mlist(char *hostp, char *dirp); 17592882Simpstruct dirlist *dirp_search(struct dirlist *, char *); 17692882Simpint do_mount(struct exportlist *, struct grouplist *, int, 17792882Simp struct xucred *, char *, int, struct statfs *); 17892882Simpint do_opt(char **, char **, struct exportlist *, struct grouplist *, 17992882Simp int *, int *, struct xucred *); 18092882Simpstruct exportlist *ex_search(fsid_t *); 18192882Simpstruct exportlist *get_exp(void); 18292882Simpvoid free_dir(struct dirlist *); 18392882Simpvoid free_exp(struct exportlist *); 18492882Simpvoid free_grp(struct grouplist *); 18592882Simpvoid free_host(struct hostlist *); 18692882Simpvoid get_exportlist(void); 18792882Simpint get_host(char *, struct grouplist *, struct grouplist *); 18892882Simpstruct hostlist *get_ht(void); 18992882Simpint get_line(void); 19092882Simpvoid get_mountlist(void); 19192882Simpint get_net(char *, struct netmsk *, int); 19292882Simpvoid getexp_err(struct exportlist *, struct grouplist *); 19392882Simpstruct grouplist *get_grp(void); 19492882Simpvoid hang_dirp(struct dirlist *, struct grouplist *, 19592882Simp struct exportlist *, int); 19675754Siedowsevoid huphandler(int sig); 19775801Siedowseint makemask(struct sockaddr_storage *ssp, int bitlen); 19892882Simpvoid mntsrv(struct svc_req *, SVCXPRT *); 19992882Simpvoid nextfield(char **, char **); 20092882Simpvoid out_of_mem(void); 20192882Simpvoid parsecred(char *, struct xucred *); 202100117Salfredint put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 20375801Siedowsevoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 20475801Siedowseint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 20575801Siedowse struct sockaddr *samask); 20692882Simpint scan_tree(struct dirlist *, struct sockaddr *); 20792882Simpstatic void usage(void); 20892882Simpint xdr_dir(XDR *, char *); 20992882Simpint xdr_explist(XDR *, caddr_t); 210100117Salfredint xdr_explist_brief(XDR *, caddr_t); 21192882Simpint xdr_fhs(XDR *, caddr_t); 21292882Simpint xdr_mlist(XDR *, caddr_t); 21392882Simpvoid terminate(int); 2141558Srgrimes 2151558Srgrimesstruct exportlist *exphead; 2161558Srgrimesstruct mountlist *mlhead; 2171558Srgrimesstruct grouplist *grphead; 2181558Srgrimeschar exname[MAXPATHLEN]; 21972650Sgreenstruct xucred def_anon = { 22091354Sdd XUCRED_VERSION, 22172650Sgreen (uid_t)-2, 2221558Srgrimes 1, 22372650Sgreen { (gid_t)-2 }, 22472650Sgreen NULL 2251558Srgrimes}; 22625087Sdfrint force_v2 = 0; 2279336Sdfrint resvport_only = 1; 2289336Sdfrint dir_only = 1; 229121767Speterint dolog = 0; 23075754Siedowseint got_sighup = 0; 23174462Salfred 2321558Srgrimesint opt_flags; 23374462Salfredstatic int have_v6 = 1; 23474462Salfred#ifdef NI_WITHSCOPEID 23574462Salfredstatic const int ninumeric = NI_NUMERICHOST | NI_WITHSCOPEID; 23674462Salfred#else 23774462Salfredstatic const int ninumeric = NI_NUMERICHOST; 23874462Salfred#endif 23974462Salfred 24074462Salfredint mountdlockfd; 24175801Siedowse/* Bits for opt_flags above */ 2421558Srgrimes#define OP_MAPROOT 0x01 2431558Srgrimes#define OP_MAPALL 0x02 24483653Speter/* 0x4 free */ 2451558Srgrimes#define OP_MASK 0x08 2461558Srgrimes#define OP_NET 0x10 2471558Srgrimes#define OP_ALLDIRS 0x40 24875801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 249100336Sjoerg#define OP_QUIET 0x100 25074462Salfred#define OP_MASKLEN 0x200 2511558Srgrimes 2521558Srgrimes#ifdef DEBUG 2531558Srgrimesint debug = 1; 25492882Simpvoid SYSLOG(int, const char *, ...) __printflike(2, 3); 2551558Srgrimes#define syslog SYSLOG 2561558Srgrimes#else 2571558Srgrimesint debug = 0; 2581558Srgrimes#endif 2591558Srgrimes 2601558Srgrimes/* 2611558Srgrimes * Mountd server for NFS mount protocol as described in: 2621558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 2631558Srgrimes * The optional arguments are the exports file name 2641558Srgrimes * default: _PATH_EXPORTS 2651558Srgrimes * and "-n" to allow nonroot mount. 2661558Srgrimes */ 2671558Srgrimesint 2681558Srgrimesmain(argc, argv) 2691558Srgrimes int argc; 2701558Srgrimes char **argv; 2711558Srgrimes{ 27275754Siedowse fd_set readfds; 273126572Sbms struct sockaddr_in sin; 274126572Sbms struct sockaddr_in6 sin6; 275126572Sbms char *endptr; 27674462Salfred SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; 27774462Salfred struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 27874462Salfred int udpsock, tcpsock, udp6sock, tcp6sock; 27974462Salfred int xcreated = 0, s; 280109363Smbr int maxrec = RPC_MAXDATASIZE; 28174462Salfred int one = 1; 282126572Sbms int c, r; 283126572Sbms in_port_t svcport = 0; 2841558Srgrimes 28575635Siedowse udp6conf = tcp6conf = NULL; 28675635Siedowse udp6sock = tcp6sock = NULL; 28775635Siedowse 28874462Salfred /* Check that another mountd isn't already running. */ 28974462Salfred if ((mountdlockfd = (open(MOUNTDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) 29074462Salfred err(1, "%s", MOUNTDLOCK); 29174462Salfred 29274462Salfred if(flock(mountdlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) 293105267Scharnier errx(1, "another mountd is already running. Aborting"); 29474462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 29574462Salfred if (s < 0) 29674462Salfred have_v6 = 0; 29774462Salfred else 29874462Salfred close(s); 29983687Speter if (modfind("nfsserver") < 0) { 30083687Speter /* Not present in kernel, try loading it */ 30183687Speter if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 30283687Speter errx(1, "NFS server is not available or loadable"); 3032999Swollman } 3042999Swollman 305126572Sbms while ((c = getopt(argc, argv, "2dlnp:r")) != -1) 3061558Srgrimes switch (c) { 30725087Sdfr case '2': 30825087Sdfr force_v2 = 1; 30925087Sdfr break; 3109336Sdfr case 'n': 3119336Sdfr resvport_only = 0; 3129336Sdfr break; 3139336Sdfr case 'r': 3149336Sdfr dir_only = 0; 3159336Sdfr break; 3168688Sphk case 'd': 3178688Sphk debug = debug ? 0 : 1; 3188688Sphk break; 31931656Sguido case 'l': 320121767Speter dolog = 1; 32131656Sguido break; 322126572Sbms case 'p': 323126572Sbms endptr = NULL; 324126572Sbms svcport = (in_port_t)strtoul(optarg, &endptr, 10); 325126572Sbms if (endptr == NULL || *endptr != '\0' || 326126572Sbms svcport == 0 || svcport >= IPPORT_MAX) 327126572Sbms usage(); 328126572Sbms break; 3291558Srgrimes default: 33037663Scharnier usage(); 3311558Srgrimes }; 3321558Srgrimes argc -= optind; 3331558Srgrimes argv += optind; 3341558Srgrimes grphead = (struct grouplist *)NULL; 3351558Srgrimes exphead = (struct exportlist *)NULL; 3361558Srgrimes mlhead = (struct mountlist *)NULL; 3371558Srgrimes if (argc == 1) { 3381558Srgrimes strncpy(exname, *argv, MAXPATHLEN-1); 3391558Srgrimes exname[MAXPATHLEN-1] = '\0'; 3401558Srgrimes } else 3411558Srgrimes strcpy(exname, _PATH_EXPORTS); 3421558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 3431558Srgrimes if (debug) 34437663Scharnier warnx("getting export list"); 3451558Srgrimes get_exportlist(); 3461558Srgrimes if (debug) 34737663Scharnier warnx("getting mount list"); 3481558Srgrimes get_mountlist(); 3491558Srgrimes if (debug) 35037663Scharnier warnx("here we go"); 3511558Srgrimes if (debug == 0) { 3521558Srgrimes daemon(0, 0); 3531558Srgrimes signal(SIGINT, SIG_IGN); 3541558Srgrimes signal(SIGQUIT, SIG_IGN); 3551558Srgrimes } 35675754Siedowse signal(SIGHUP, huphandler); 35774462Salfred signal(SIGTERM, terminate); 3581558Srgrimes { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 3591558Srgrimes if (pidfile != NULL) { 3601558Srgrimes fprintf(pidfile, "%d\n", getpid()); 3611558Srgrimes fclose(pidfile); 3621558Srgrimes } 3631558Srgrimes } 36474462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 36574462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 36674462Salfred udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 36774462Salfred tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 36874791Salfred udpconf = getnetconfigent("udp"); 36974791Salfred tcpconf = getnetconfigent("tcp"); 370109363Smbr 371109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 372109363Smbr 37374791Salfred if (!have_v6) 37474791Salfred goto skip_v6; 37574462Salfred udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 37674462Salfred tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 37774462Salfred /* 37874462Salfred * We're doing host-based access checks here, so don't allow 37974462Salfred * v4-in-v6 to confuse things. The kernel will disable it 38074462Salfred * by default on NFS sockets too. 38174462Salfred */ 38274462Salfred if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6, 383117684Srwatson IPV6_V6ONLY, &one, sizeof one) < 0) { 38474462Salfred syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 38574462Salfred exit(1); 38674462Salfred } 38774462Salfred if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6, 388117684Srwatson IPV6_V6ONLY, &one, sizeof one) < 0) { 389117684Srwatson syslog(LOG_ERR, "can't disable v4-in-v6 on TCP socket"); 39074462Salfred exit(1); 39174462Salfred } 39274462Salfred udp6conf = getnetconfigent("udp6"); 39374462Salfred tcp6conf = getnetconfigent("tcp6"); 39474791Salfred 39574791Salfredskip_v6: 39624759Sguido if (!resvport_only) { 39783687Speter if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 39883687Speter &resvport_only, sizeof(resvport_only)) != 0 && 39983687Speter errno != ENOENT) { 40024759Sguido syslog(LOG_ERR, "sysctl: %m"); 40124759Sguido exit(1); 40224759Sguido } 40324330Sguido } 404126572Sbms if (svcport != 0) { 405126572Sbms bzero(&sin, sizeof(struct sockaddr_in)); 406126572Sbms sin.sin_len = sizeof(struct sockaddr_in); 407126572Sbms sin.sin_family = AF_INET; 408126572Sbms sin.sin_port = htons(svcport); 409126572Sbms 410126572Sbms bzero(&sin6, sizeof(struct sockaddr_in6)); 411126572Sbms sin6.sin6_len = sizeof(struct sockaddr_in6); 412126572Sbms sin6.sin6_family = AF_INET6; 413126572Sbms sin6.sin6_port = htons(svcport); 414126572Sbms } 41574462Salfred if (udpsock != -1 && udpconf != NULL) { 416126572Sbms if (svcport != 0) { 417126572Sbms r = bindresvport(udpsock, &sin); 418126572Sbms if (r != 0) { 419126572Sbms syslog(LOG_ERR, "bindresvport: %m"); 420126572Sbms exit(1); 421126572Sbms } 422126572Sbms } else 423126572Sbms (void)bindresvport(udpsock, NULL); 42474462Salfred udptransp = svc_dg_create(udpsock, 0, 0); 42574462Salfred if (udptransp != NULL) { 42674462Salfred if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, 42774462Salfred mntsrv, udpconf)) 42874462Salfred syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service"); 42974462Salfred else 43074462Salfred xcreated++; 43174462Salfred if (!force_v2) { 43274462Salfred if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3, 43374462Salfred mntsrv, udpconf)) 43474462Salfred syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service"); 43574462Salfred else 43674462Salfred xcreated++; 43774462Salfred } 43874462Salfred } else 43974462Salfred syslog(LOG_WARNING, "can't create UDP services"); 44074462Salfred 44174462Salfred } 44274462Salfred if (tcpsock != -1 && tcpconf != NULL) { 443126572Sbms if (svcport != 0) { 444126572Sbms r = bindresvport(tcpsock, &sin); 445126572Sbms if (r != 0) { 446126572Sbms syslog(LOG_ERR, "bindresvport: %m"); 447126572Sbms exit(1); 448126572Sbms } 449126572Sbms } else 450126572Sbms (void)bindresvport(tcpsock, NULL); 45174462Salfred listen(tcpsock, SOMAXCONN); 452109363Smbr tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 45374462Salfred if (tcptransp != NULL) { 45474462Salfred if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1, 45574462Salfred mntsrv, tcpconf)) 45674462Salfred syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service"); 45774462Salfred else 45874462Salfred xcreated++; 45974462Salfred if (!force_v2) { 46074462Salfred if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3, 46174462Salfred mntsrv, tcpconf)) 46274462Salfred syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service"); 46374462Salfred else 46474462Salfred xcreated++; 46574462Salfred } 46674462Salfred } else 46774462Salfred syslog(LOG_WARNING, "can't create TCP service"); 46874462Salfred 46974462Salfred } 47074791Salfred if (have_v6 && udp6sock != -1 && udp6conf != NULL) { 471126572Sbms if (svcport != 0) { 472126572Sbms r = bindresvport_sa(udp6sock, 473126572Sbms (struct sockaddr *)&sin6); 474126572Sbms if (r != 0) { 475126572Sbms syslog(LOG_ERR, "bindresvport_sa: %m"); 476126572Sbms exit(1); 477126572Sbms } 478126572Sbms } else 479126572Sbms (void)bindresvport_sa(udp6sock, NULL); 48074462Salfred udp6transp = svc_dg_create(udp6sock, 0, 0); 48174462Salfred if (udp6transp != NULL) { 48274462Salfred if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, 48374462Salfred mntsrv, udp6conf)) 48474462Salfred syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service"); 48574462Salfred else 48674462Salfred xcreated++; 48774462Salfred if (!force_v2) { 48874462Salfred if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3, 48974462Salfred mntsrv, udp6conf)) 49074462Salfred syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service"); 49174462Salfred else 49274462Salfred xcreated++; 49374462Salfred } 49474462Salfred } else 49574462Salfred syslog(LOG_WARNING, "can't create UDP6 service"); 49674462Salfred 49774462Salfred } 49874791Salfred if (have_v6 && tcp6sock != -1 && tcp6conf != NULL) { 499126572Sbms if (svcport != 0) { 500126572Sbms r = bindresvport_sa(tcp6sock, 501126572Sbms (struct sockaddr *)&sin6); 502126572Sbms if (r != 0) { 503126572Sbms syslog(LOG_ERR, "bindresvport_sa: %m"); 504126572Sbms exit(1); 505126572Sbms } 506126572Sbms } else 507126572Sbms (void)bindresvport_sa(tcp6sock, NULL); 50874462Salfred listen(tcp6sock, SOMAXCONN); 509109363Smbr tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 51074462Salfred if (tcp6transp != NULL) { 51174462Salfred if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1, 51274462Salfred mntsrv, tcp6conf)) 51374462Salfred syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service"); 51474462Salfred else 51574462Salfred xcreated++; 51674462Salfred if (!force_v2) { 51774462Salfred if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3, 51874462Salfred mntsrv, tcp6conf)) 51974462Salfred syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service"); 52074462Salfred else 52174462Salfred xcreated++; 52274462Salfred } 52374462Salfred } else 52474462Salfred syslog(LOG_WARNING, "can't create TCP6 service"); 52574462Salfred 52674462Salfred } 52774462Salfred if (xcreated == 0) { 52874462Salfred syslog(LOG_ERR, "could not create any services"); 5291558Srgrimes exit(1); 5301558Srgrimes } 53175754Siedowse 53275754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 53375754Siedowse for (;;) { 53475754Siedowse if (got_sighup) { 53575754Siedowse get_exportlist(); 53675754Siedowse got_sighup = 0; 53775754Siedowse } 53875754Siedowse readfds = svc_fdset; 53975754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 54075754Siedowse case -1: 54175754Siedowse if (errno == EINTR) 54275754Siedowse continue; 54375754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 54475754Siedowse exit(1); 54575754Siedowse case 0: 54675754Siedowse continue; 54775754Siedowse default: 54875754Siedowse svc_getreqset(&readfds); 54975754Siedowse } 55075754Siedowse } 5511558Srgrimes} 5521558Srgrimes 55337663Scharnierstatic void 55437663Scharnierusage() 55537663Scharnier{ 55637663Scharnier fprintf(stderr, 557126572Sbms "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] " 558126572Sbms "[export_file]\n"); 55937663Scharnier exit(1); 56037663Scharnier} 56137663Scharnier 5621558Srgrimes/* 5631558Srgrimes * The mount rpc service 5641558Srgrimes */ 5651558Srgrimesvoid 5661558Srgrimesmntsrv(rqstp, transp) 5671558Srgrimes struct svc_req *rqstp; 5681558Srgrimes SVCXPRT *transp; 5691558Srgrimes{ 5701558Srgrimes struct exportlist *ep; 5711558Srgrimes struct dirlist *dp; 5729336Sdfr struct fhreturn fhr; 5731558Srgrimes struct stat stb; 5741558Srgrimes struct statfs fsb; 57574462Salfred struct addrinfo *ai; 57674462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 57774462Salfred int lookup_failed = 1; 57874462Salfred struct sockaddr *saddr; 5799336Sdfr u_short sport; 58023681Speter char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 58128911Sguido int bad = 0, defset, hostset; 5829336Sdfr sigset_t sighup_mask; 5831558Srgrimes 5849336Sdfr sigemptyset(&sighup_mask); 5859336Sdfr sigaddset(&sighup_mask, SIGHUP); 58674462Salfred saddr = svc_getrpccaller(transp)->buf; 58774462Salfred switch (saddr->sa_family) { 58874462Salfred case AF_INET6: 58975635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 59074462Salfred break; 59174462Salfred case AF_INET: 59275635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 59374462Salfred break; 59474462Salfred default: 59574462Salfred syslog(LOG_ERR, "request from unknown address family"); 59674462Salfred return; 59774462Salfred } 59874462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 59974462Salfred NULL, 0, 0); 60074462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 60174462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 60274462Salfred ai = NULL; 6031558Srgrimes switch (rqstp->rq_proc) { 6041558Srgrimes case NULLPROC: 605121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 60637663Scharnier syslog(LOG_ERR, "can't send reply"); 6071558Srgrimes return; 6081558Srgrimes case RPCMNT_MOUNT: 6099336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 61031656Sguido syslog(LOG_NOTICE, 61131656Sguido "mount request from %s from unprivileged port", 61274462Salfred numerichost); 6131558Srgrimes svcerr_weakauth(transp); 6141558Srgrimes return; 6151558Srgrimes } 616121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 61731656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 61874462Salfred numerichost); 6191558Srgrimes svcerr_decode(transp); 6201558Srgrimes return; 6211558Srgrimes } 6221558Srgrimes 6231558Srgrimes /* 6241558Srgrimes * Get the real pathname and make sure it is a directory 6259336Sdfr * or a regular file if the -r option was specified 6269336Sdfr * and it exists. 6271558Srgrimes */ 62851968Salfred if (realpath(rpcpath, dirpath) == NULL || 6291558Srgrimes stat(dirpath, &stb) < 0 || 6309336Sdfr (!S_ISDIR(stb.st_mode) && 63174462Salfred (dir_only || !S_ISREG(stb.st_mode))) || 6321558Srgrimes statfs(dirpath, &fsb) < 0) { 6331558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 63431656Sguido syslog(LOG_NOTICE, 63537663Scharnier "mount request from %s for non existent path %s", 63674462Salfred numerichost, dirpath); 6371558Srgrimes if (debug) 63837663Scharnier warnx("stat failed on %s", dirpath); 63928911Sguido bad = ENOENT; /* We will send error reply later */ 6401558Srgrimes } 6411558Srgrimes 6421558Srgrimes /* Check in the exports list */ 6439336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 6441558Srgrimes ep = ex_search(&fsb.f_fsid); 6459336Sdfr hostset = defset = 0; 6469336Sdfr if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 6471558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 64874462Salfred chk_host(dp, saddr, &defset, &hostset)) || 64974462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 65074462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 65128911Sguido if (bad) { 652121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 65328911Sguido (caddr_t)&bad)) 65437663Scharnier syslog(LOG_ERR, "can't send reply"); 65528911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 65628911Sguido return; 65728911Sguido } 6589336Sdfr if (hostset & DP_HOSTSET) 6599336Sdfr fhr.fhr_flag = hostset; 6609336Sdfr else 6619336Sdfr fhr.fhr_flag = defset; 6629336Sdfr fhr.fhr_vers = rqstp->rq_vers; 6631558Srgrimes /* Get the file handle */ 66423681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 6659336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 6661558Srgrimes bad = errno; 66737663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 668121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 6691558Srgrimes (caddr_t)&bad)) 67037663Scharnier syslog(LOG_ERR, "can't send reply"); 6719336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 6721558Srgrimes return; 6731558Srgrimes } 674121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 675121556Speter (caddr_t)&fhr)) 67637663Scharnier syslog(LOG_ERR, "can't send reply"); 67774462Salfred if (!lookup_failed) 67874462Salfred add_mlist(host, dirpath); 6791558Srgrimes else 68074462Salfred add_mlist(numerichost, dirpath); 6811558Srgrimes if (debug) 68237663Scharnier warnx("mount successful"); 683121767Speter if (dolog) 68431656Sguido syslog(LOG_NOTICE, 68531656Sguido "mount request succeeded from %s for %s", 68674462Salfred numerichost, dirpath); 68731656Sguido } else { 6881558Srgrimes bad = EACCES; 68931656Sguido syslog(LOG_NOTICE, 69031656Sguido "mount request denied from %s for %s", 69174462Salfred numerichost, dirpath); 69231656Sguido } 69328911Sguido 694121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 695121556Speter (caddr_t)&bad)) 69637663Scharnier syslog(LOG_ERR, "can't send reply"); 6979336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 6981558Srgrimes return; 6991558Srgrimes case RPCMNT_DUMP: 700121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 70137663Scharnier syslog(LOG_ERR, "can't send reply"); 702121767Speter else if (dolog) 70331656Sguido syslog(LOG_NOTICE, 70431656Sguido "dump request succeeded from %s", 70574462Salfred numerichost); 7061558Srgrimes return; 7071558Srgrimes case RPCMNT_UMOUNT: 7089336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 70931656Sguido syslog(LOG_NOTICE, 71031656Sguido "umount request from %s from unprivileged port", 71174462Salfred numerichost); 7121558Srgrimes svcerr_weakauth(transp); 7131558Srgrimes return; 7141558Srgrimes } 715121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 71631656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 71774462Salfred numerichost); 7181558Srgrimes svcerr_decode(transp); 7191558Srgrimes return; 7201558Srgrimes } 72151968Salfred if (realpath(rpcpath, dirpath) == NULL) { 72251968Salfred syslog(LOG_NOTICE, "umount request from %s " 72351968Salfred "for non existent path %s", 72474462Salfred numerichost, dirpath); 72551968Salfred } 726121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 72737663Scharnier syslog(LOG_ERR, "can't send reply"); 72874462Salfred if (!lookup_failed) 72975635Siedowse del_mlist(host, dirpath); 73075635Siedowse del_mlist(numerichost, dirpath); 731121767Speter if (dolog) 73231656Sguido syslog(LOG_NOTICE, 73331656Sguido "umount request succeeded from %s for %s", 73474462Salfred numerichost, dirpath); 7351558Srgrimes return; 7361558Srgrimes case RPCMNT_UMNTALL: 7379336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 73831656Sguido syslog(LOG_NOTICE, 73931656Sguido "umountall request from %s from unprivileged port", 74074462Salfred numerichost); 7411558Srgrimes svcerr_weakauth(transp); 7421558Srgrimes return; 7431558Srgrimes } 744121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 74537663Scharnier syslog(LOG_ERR, "can't send reply"); 74674462Salfred if (!lookup_failed) 74775635Siedowse del_mlist(host, NULL); 74875635Siedowse del_mlist(numerichost, NULL); 749121767Speter if (dolog) 75031656Sguido syslog(LOG_NOTICE, 75131656Sguido "umountall request succeeded from %s", 75274462Salfred numerichost); 7531558Srgrimes return; 7541558Srgrimes case RPCMNT_EXPORT: 755121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 756121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 757121556Speter (caddr_t)NULL)) 758100117Salfred syslog(LOG_ERR, "can't send reply"); 759121767Speter if (dolog) 76031656Sguido syslog(LOG_NOTICE, 76131656Sguido "export request succeeded from %s", 76274462Salfred numerichost); 7631558Srgrimes return; 7641558Srgrimes default: 7651558Srgrimes svcerr_noproc(transp); 7661558Srgrimes return; 7671558Srgrimes } 7681558Srgrimes} 7691558Srgrimes 7701558Srgrimes/* 7711558Srgrimes * Xdr conversion for a dirpath string 7721558Srgrimes */ 7731558Srgrimesint 7741558Srgrimesxdr_dir(xdrsp, dirp) 7751558Srgrimes XDR *xdrsp; 7761558Srgrimes char *dirp; 7771558Srgrimes{ 7781558Srgrimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 7791558Srgrimes} 7801558Srgrimes 7811558Srgrimes/* 7829336Sdfr * Xdr routine to generate file handle reply 7831558Srgrimes */ 7841558Srgrimesint 7859336Sdfrxdr_fhs(xdrsp, cp) 7861558Srgrimes XDR *xdrsp; 7879336Sdfr caddr_t cp; 7881558Srgrimes{ 78992806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 7909336Sdfr u_long ok = 0, len, auth; 7911558Srgrimes 7921558Srgrimes if (!xdr_long(xdrsp, &ok)) 7931558Srgrimes return (0); 7949336Sdfr switch (fhrp->fhr_vers) { 7959336Sdfr case 1: 7969336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 7979336Sdfr case 3: 7989336Sdfr len = NFSX_V3FH; 7999336Sdfr if (!xdr_long(xdrsp, &len)) 8009336Sdfr return (0); 8019336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 8029336Sdfr return (0); 80383653Speter auth = RPCAUTH_UNIX; 8049336Sdfr len = 1; 8059336Sdfr if (!xdr_long(xdrsp, &len)) 8069336Sdfr return (0); 8079336Sdfr return (xdr_long(xdrsp, &auth)); 8089336Sdfr }; 8099336Sdfr return (0); 8101558Srgrimes} 8111558Srgrimes 8121558Srgrimesint 8131558Srgrimesxdr_mlist(xdrsp, cp) 8141558Srgrimes XDR *xdrsp; 8151558Srgrimes caddr_t cp; 8161558Srgrimes{ 8171558Srgrimes struct mountlist *mlp; 8181558Srgrimes int true = 1; 8191558Srgrimes int false = 0; 8201558Srgrimes char *strp; 8211558Srgrimes 8221558Srgrimes mlp = mlhead; 8231558Srgrimes while (mlp) { 8241558Srgrimes if (!xdr_bool(xdrsp, &true)) 8251558Srgrimes return (0); 8261558Srgrimes strp = &mlp->ml_host[0]; 8271558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 8281558Srgrimes return (0); 8291558Srgrimes strp = &mlp->ml_dirp[0]; 8301558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 8311558Srgrimes return (0); 8321558Srgrimes mlp = mlp->ml_next; 8331558Srgrimes } 8341558Srgrimes if (!xdr_bool(xdrsp, &false)) 8351558Srgrimes return (0); 8361558Srgrimes return (1); 8371558Srgrimes} 8381558Srgrimes 8391558Srgrimes/* 8401558Srgrimes * Xdr conversion for export list 8411558Srgrimes */ 8421558Srgrimesint 843100117Salfredxdr_explist_common(xdrsp, cp, brief) 8441558Srgrimes XDR *xdrsp; 8451558Srgrimes caddr_t cp; 846100117Salfred int brief; 8471558Srgrimes{ 8481558Srgrimes struct exportlist *ep; 8491558Srgrimes int false = 0; 8509336Sdfr int putdef; 8519336Sdfr sigset_t sighup_mask; 8521558Srgrimes 8539336Sdfr sigemptyset(&sighup_mask); 8549336Sdfr sigaddset(&sighup_mask, SIGHUP); 8559336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 8561558Srgrimes ep = exphead; 8571558Srgrimes while (ep) { 8581558Srgrimes putdef = 0; 859100117Salfred if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 860100117Salfred &putdef, brief)) 8611558Srgrimes goto errout; 8621558Srgrimes if (ep->ex_defdir && putdef == 0 && 8631558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 864100117Salfred &putdef, brief)) 8651558Srgrimes goto errout; 8661558Srgrimes ep = ep->ex_next; 8671558Srgrimes } 8689336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8691558Srgrimes if (!xdr_bool(xdrsp, &false)) 8701558Srgrimes return (0); 8711558Srgrimes return (1); 8721558Srgrimeserrout: 8739336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8741558Srgrimes return (0); 8751558Srgrimes} 8761558Srgrimes 8771558Srgrimes/* 8781558Srgrimes * Called from xdr_explist() to traverse the tree and export the 8791558Srgrimes * directory paths. 8801558Srgrimes */ 8811558Srgrimesint 882100117Salfredput_exlist(dp, xdrsp, adp, putdefp, brief) 8831558Srgrimes struct dirlist *dp; 8841558Srgrimes XDR *xdrsp; 8851558Srgrimes struct dirlist *adp; 8861558Srgrimes int *putdefp; 887100117Salfred int brief; 8881558Srgrimes{ 8891558Srgrimes struct grouplist *grp; 8901558Srgrimes struct hostlist *hp; 8911558Srgrimes int true = 1; 8921558Srgrimes int false = 0; 8931558Srgrimes int gotalldir = 0; 8941558Srgrimes char *strp; 8951558Srgrimes 8961558Srgrimes if (dp) { 897100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 8981558Srgrimes return (1); 8991558Srgrimes if (!xdr_bool(xdrsp, &true)) 9001558Srgrimes return (1); 9011558Srgrimes strp = dp->dp_dirp; 9021558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 9031558Srgrimes return (1); 9041558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 9051558Srgrimes gotalldir = 1; 9061558Srgrimes *putdefp = 1; 9071558Srgrimes } 908100117Salfred if (brief) { 909100117Salfred if (!xdr_bool(xdrsp, &true)) 910100117Salfred return (1); 911100117Salfred strp = "(...)"; 912100117Salfred if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 913100117Salfred return (1); 914100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 9151558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 9161558Srgrimes hp = dp->dp_hosts; 9171558Srgrimes while (hp) { 9181558Srgrimes grp = hp->ht_grp; 9191558Srgrimes if (grp->gr_type == GT_HOST) { 9201558Srgrimes if (!xdr_bool(xdrsp, &true)) 9211558Srgrimes return (1); 92274462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 9238871Srgrimes if (!xdr_string(xdrsp, &strp, 9241558Srgrimes RPCMNT_NAMELEN)) 9251558Srgrimes return (1); 9261558Srgrimes } else if (grp->gr_type == GT_NET) { 9271558Srgrimes if (!xdr_bool(xdrsp, &true)) 9281558Srgrimes return (1); 9291558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 9308871Srgrimes if (!xdr_string(xdrsp, &strp, 9311558Srgrimes RPCMNT_NAMELEN)) 9321558Srgrimes return (1); 9331558Srgrimes } 9341558Srgrimes hp = hp->ht_next; 9351558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 9361558Srgrimes hp = adp->dp_hosts; 9371558Srgrimes gotalldir = 0; 9381558Srgrimes } 9391558Srgrimes } 9401558Srgrimes } 9411558Srgrimes if (!xdr_bool(xdrsp, &false)) 9421558Srgrimes return (1); 943100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 9441558Srgrimes return (1); 9451558Srgrimes } 9461558Srgrimes return (0); 9471558Srgrimes} 9481558Srgrimes 949100117Salfredint 950100117Salfredxdr_explist(xdrsp, cp) 951100117Salfred XDR *xdrsp; 952100117Salfred caddr_t cp; 953100117Salfred{ 954100117Salfred 955100117Salfred return xdr_explist_common(xdrsp, cp, 0); 956100117Salfred} 957100117Salfred 958100117Salfredint 959100117Salfredxdr_explist_brief(xdrsp, cp) 960100117Salfred XDR *xdrsp; 961100117Salfred caddr_t cp; 962100117Salfred{ 963100117Salfred 964100117Salfred return xdr_explist_common(xdrsp, cp, 1); 965100117Salfred} 966100117Salfred 96796622Siedowsechar *line; 96896622Siedowseint linesize; 9691558SrgrimesFILE *exp_file; 9701558Srgrimes 9711558Srgrimes/* 9721558Srgrimes * Get the export list 9731558Srgrimes */ 9741558Srgrimesvoid 9751558Srgrimesget_exportlist() 9761558Srgrimes{ 9771558Srgrimes struct exportlist *ep, *ep2; 9781558Srgrimes struct grouplist *grp, *tgrp; 9791558Srgrimes struct exportlist **epp; 9801558Srgrimes struct dirlist *dirhead; 9811558Srgrimes struct statfs fsb, *fsp; 98272650Sgreen struct xucred anon; 9831558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 9841558Srgrimes int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 9851558Srgrimes 98651968Salfred dirp = NULL; 98751968Salfred dirplen = 0; 98851968Salfred 9891558Srgrimes /* 9901558Srgrimes * First, get rid of the old list 9911558Srgrimes */ 9921558Srgrimes ep = exphead; 9931558Srgrimes while (ep) { 9941558Srgrimes ep2 = ep; 9951558Srgrimes ep = ep->ex_next; 9961558Srgrimes free_exp(ep2); 9971558Srgrimes } 9981558Srgrimes exphead = (struct exportlist *)NULL; 9991558Srgrimes 10001558Srgrimes grp = grphead; 10011558Srgrimes while (grp) { 10021558Srgrimes tgrp = grp; 10031558Srgrimes grp = grp->gr_next; 10041558Srgrimes free_grp(tgrp); 10051558Srgrimes } 10061558Srgrimes grphead = (struct grouplist *)NULL; 10071558Srgrimes 10081558Srgrimes /* 10091558Srgrimes * And delete exports that are in the kernel for all local 101096707Strhodes * filesystems. 101196707Strhodes * XXX: Should know how to handle all local exportable filesystems 101223681Speter * instead of just "ufs". 10131558Srgrimes */ 10141558Srgrimes num = getmntinfo(&fsp, MNT_NOWAIT); 10151558Srgrimes for (i = 0; i < num; i++) { 10161558Srgrimes union { 10171558Srgrimes struct ufs_args ua; 10181558Srgrimes struct iso_args ia; 10199336Sdfr struct msdosfs_args da; 102054093Ssemenu struct ntfs_args na; 10211558Srgrimes } targs; 10221558Srgrimes 102377435Sphk if (!strcmp(fsp->f_fstypename, "ufs") || 102477577Sru !strcmp(fsp->f_fstypename, "msdosfs") || 102554093Ssemenu !strcmp(fsp->f_fstypename, "ntfs") || 102623681Speter !strcmp(fsp->f_fstypename, "cd9660")) { 10279336Sdfr targs.ua.fspec = NULL; 10289336Sdfr targs.ua.export.ex_flags = MNT_DELEXPORT; 10299336Sdfr if (mount(fsp->f_fstypename, fsp->f_mntonname, 103077405Siedowse fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0 && 103177405Siedowse errno != ENOENT) 103277405Siedowse syslog(LOG_ERR, 103377405Siedowse "can't delete exports for %s: %m", 103474462Salfred fsp->f_mntonname); 10351558Srgrimes } 10361558Srgrimes fsp++; 10371558Srgrimes } 10381558Srgrimes 10391558Srgrimes /* 10401558Srgrimes * Read in the exports file and build the list, calling 10411558Srgrimes * mount() as we go along to push the export rules into the kernel. 10421558Srgrimes */ 10431558Srgrimes if ((exp_file = fopen(exname, "r")) == NULL) { 104437663Scharnier syslog(LOG_ERR, "can't open %s", exname); 10451558Srgrimes exit(2); 10461558Srgrimes } 10471558Srgrimes dirhead = (struct dirlist *)NULL; 10481558Srgrimes while (get_line()) { 10491558Srgrimes if (debug) 105037663Scharnier warnx("got line %s", line); 10511558Srgrimes cp = line; 10521558Srgrimes nextfield(&cp, &endcp); 10531558Srgrimes if (*cp == '#') 10541558Srgrimes goto nextline; 10551558Srgrimes 10561558Srgrimes /* 10571558Srgrimes * Set defaults. 10581558Srgrimes */ 10591558Srgrimes has_host = FALSE; 10601558Srgrimes anon = def_anon; 10611558Srgrimes exflags = MNT_EXPORTED; 10621558Srgrimes got_nondir = 0; 10631558Srgrimes opt_flags = 0; 10641558Srgrimes ep = (struct exportlist *)NULL; 10651558Srgrimes 10661558Srgrimes /* 10671558Srgrimes * Create new exports list entry 10681558Srgrimes */ 10691558Srgrimes len = endcp-cp; 10701558Srgrimes tgrp = grp = get_grp(); 10711558Srgrimes while (len > 0) { 10721558Srgrimes if (len > RPCMNT_NAMELEN) { 10731558Srgrimes getexp_err(ep, tgrp); 10741558Srgrimes goto nextline; 10751558Srgrimes } 10761558Srgrimes if (*cp == '-') { 10771558Srgrimes if (ep == (struct exportlist *)NULL) { 10781558Srgrimes getexp_err(ep, tgrp); 10791558Srgrimes goto nextline; 10801558Srgrimes } 10811558Srgrimes if (debug) 108237663Scharnier warnx("doing opt %s", cp); 10831558Srgrimes got_nondir = 1; 10841558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 10851558Srgrimes &exflags, &anon)) { 10861558Srgrimes getexp_err(ep, tgrp); 10871558Srgrimes goto nextline; 10881558Srgrimes } 10891558Srgrimes } else if (*cp == '/') { 10901558Srgrimes savedc = *endcp; 10911558Srgrimes *endcp = '\0'; 10921558Srgrimes if (check_dirpath(cp) && 10931558Srgrimes statfs(cp, &fsb) >= 0) { 10941558Srgrimes if (got_nondir) { 109537663Scharnier syslog(LOG_ERR, "dirs must be first"); 10961558Srgrimes getexp_err(ep, tgrp); 10971558Srgrimes goto nextline; 10981558Srgrimes } 10991558Srgrimes if (ep) { 11001558Srgrimes if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 11011558Srgrimes ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 11021558Srgrimes getexp_err(ep, tgrp); 11031558Srgrimes goto nextline; 11041558Srgrimes } 11051558Srgrimes } else { 11061558Srgrimes /* 11071558Srgrimes * See if this directory is already 11081558Srgrimes * in the list. 11091558Srgrimes */ 11101558Srgrimes ep = ex_search(&fsb.f_fsid); 11111558Srgrimes if (ep == (struct exportlist *)NULL) { 11121558Srgrimes ep = get_exp(); 11131558Srgrimes ep->ex_fs = fsb.f_fsid; 11141558Srgrimes ep->ex_fsdir = (char *) 11151558Srgrimes malloc(strlen(fsb.f_mntonname) + 1); 11161558Srgrimes if (ep->ex_fsdir) 11171558Srgrimes strcpy(ep->ex_fsdir, 11181558Srgrimes fsb.f_mntonname); 11191558Srgrimes else 11201558Srgrimes out_of_mem(); 11211558Srgrimes if (debug) 112274462Salfred warnx("making new ep fs=0x%x,0x%x", 112374462Salfred fsb.f_fsid.val[0], 112474462Salfred fsb.f_fsid.val[1]); 11251558Srgrimes } else if (debug) 112637663Scharnier warnx("found ep fs=0x%x,0x%x", 11271558Srgrimes fsb.f_fsid.val[0], 11281558Srgrimes fsb.f_fsid.val[1]); 11291558Srgrimes } 11301558Srgrimes 11311558Srgrimes /* 11321558Srgrimes * Add dirpath to export mount point. 11331558Srgrimes */ 11341558Srgrimes dirp = add_expdir(&dirhead, cp, len); 11351558Srgrimes dirplen = len; 11361558Srgrimes } else { 11371558Srgrimes getexp_err(ep, tgrp); 11381558Srgrimes goto nextline; 11391558Srgrimes } 11401558Srgrimes *endcp = savedc; 11411558Srgrimes } else { 11421558Srgrimes savedc = *endcp; 11431558Srgrimes *endcp = '\0'; 11441558Srgrimes got_nondir = 1; 11451558Srgrimes if (ep == (struct exportlist *)NULL) { 11461558Srgrimes getexp_err(ep, tgrp); 11471558Srgrimes goto nextline; 11481558Srgrimes } 11491558Srgrimes 11501558Srgrimes /* 11511558Srgrimes * Get the host or netgroup. 11521558Srgrimes */ 11531558Srgrimes setnetgrent(cp); 11541558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 11551558Srgrimes do { 11561558Srgrimes if (has_host) { 11571558Srgrimes grp->gr_next = get_grp(); 11581558Srgrimes grp = grp->gr_next; 11591558Srgrimes } 11601558Srgrimes if (netgrp) { 116137003Sjoerg if (hst == 0) { 116237663Scharnier syslog(LOG_ERR, 116337663Scharnier "null hostname in netgroup %s, skipping", cp); 116437004Sjoerg grp->gr_type = GT_IGNORE; 116537003Sjoerg } else if (get_host(hst, grp, tgrp)) { 116637663Scharnier syslog(LOG_ERR, 116737663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 116829317Sjlemon grp->gr_type = GT_IGNORE; 11691558Srgrimes } 11707401Swpaul } else if (get_host(cp, grp, tgrp)) { 117137663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 117229317Sjlemon grp->gr_type = GT_IGNORE; 11731558Srgrimes } 11741558Srgrimes has_host = TRUE; 11751558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 11761558Srgrimes endnetgrent(); 11771558Srgrimes *endcp = savedc; 11781558Srgrimes } 11791558Srgrimes cp = endcp; 11801558Srgrimes nextfield(&cp, &endcp); 11811558Srgrimes len = endcp - cp; 11821558Srgrimes } 11831558Srgrimes if (check_options(dirhead)) { 11841558Srgrimes getexp_err(ep, tgrp); 11851558Srgrimes goto nextline; 11861558Srgrimes } 11871558Srgrimes if (!has_host) { 118875641Siedowse grp->gr_type = GT_DEFAULT; 11891558Srgrimes if (debug) 119037663Scharnier warnx("adding a default entry"); 11911558Srgrimes 11921558Srgrimes /* 11931558Srgrimes * Don't allow a network export coincide with a list of 11941558Srgrimes * host(s) on the same line. 11951558Srgrimes */ 11961558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 119775801Siedowse syslog(LOG_ERR, "network/host conflict"); 11981558Srgrimes getexp_err(ep, tgrp); 11991558Srgrimes goto nextline; 120029317Sjlemon 120174462Salfred /* 120274462Salfred * If an export list was specified on this line, make sure 120329317Sjlemon * that we have at least one valid entry, otherwise skip it. 120429317Sjlemon */ 120529317Sjlemon } else { 120629317Sjlemon grp = tgrp; 120774462Salfred while (grp && grp->gr_type == GT_IGNORE) 120829317Sjlemon grp = grp->gr_next; 120929317Sjlemon if (! grp) { 121029317Sjlemon getexp_err(ep, tgrp); 121129317Sjlemon goto nextline; 121229317Sjlemon } 12131558Srgrimes } 12141558Srgrimes 12151558Srgrimes /* 12161558Srgrimes * Loop through hosts, pushing the exports into the kernel. 12171558Srgrimes * After loop, tgrp points to the start of the list and 12181558Srgrimes * grp points to the last entry in the list. 12191558Srgrimes */ 12201558Srgrimes grp = tgrp; 12211558Srgrimes do { 122275635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 122375635Siedowse &fsb)) { 122475635Siedowse getexp_err(ep, tgrp); 122575635Siedowse goto nextline; 122675635Siedowse } 12271558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 12281558Srgrimes 12291558Srgrimes /* 12301558Srgrimes * Success. Update the data structures. 12311558Srgrimes */ 12321558Srgrimes if (has_host) { 12339336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 12341558Srgrimes grp->gr_next = grphead; 12351558Srgrimes grphead = tgrp; 12361558Srgrimes } else { 12371558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 12389336Sdfr opt_flags); 12391558Srgrimes free_grp(grp); 12401558Srgrimes } 12411558Srgrimes dirhead = (struct dirlist *)NULL; 12421558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 12431558Srgrimes ep2 = exphead; 12441558Srgrimes epp = &exphead; 12451558Srgrimes 12461558Srgrimes /* 12471558Srgrimes * Insert in the list in alphabetical order. 12481558Srgrimes */ 12491558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 12501558Srgrimes epp = &ep2->ex_next; 12511558Srgrimes ep2 = ep2->ex_next; 12521558Srgrimes } 12531558Srgrimes if (ep2) 12541558Srgrimes ep->ex_next = ep2; 12551558Srgrimes *epp = ep; 12561558Srgrimes ep->ex_flag |= EX_LINKED; 12571558Srgrimes } 12581558Srgrimesnextline: 12591558Srgrimes if (dirhead) { 12601558Srgrimes free_dir(dirhead); 12611558Srgrimes dirhead = (struct dirlist *)NULL; 12621558Srgrimes } 12631558Srgrimes } 12641558Srgrimes fclose(exp_file); 12651558Srgrimes} 12661558Srgrimes 12671558Srgrimes/* 12681558Srgrimes * Allocate an export list element 12691558Srgrimes */ 12701558Srgrimesstruct exportlist * 12711558Srgrimesget_exp() 12721558Srgrimes{ 12731558Srgrimes struct exportlist *ep; 12741558Srgrimes 12751558Srgrimes ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 12761558Srgrimes if (ep == (struct exportlist *)NULL) 12771558Srgrimes out_of_mem(); 127823681Speter memset(ep, 0, sizeof(struct exportlist)); 12791558Srgrimes return (ep); 12801558Srgrimes} 12811558Srgrimes 12821558Srgrimes/* 12831558Srgrimes * Allocate a group list element 12841558Srgrimes */ 12851558Srgrimesstruct grouplist * 12861558Srgrimesget_grp() 12871558Srgrimes{ 12881558Srgrimes struct grouplist *gp; 12891558Srgrimes 12901558Srgrimes gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 12911558Srgrimes if (gp == (struct grouplist *)NULL) 12921558Srgrimes out_of_mem(); 129323681Speter memset(gp, 0, sizeof(struct grouplist)); 12941558Srgrimes return (gp); 12951558Srgrimes} 12961558Srgrimes 12971558Srgrimes/* 12981558Srgrimes * Clean up upon an error in get_exportlist(). 12991558Srgrimes */ 13001558Srgrimesvoid 13011558Srgrimesgetexp_err(ep, grp) 13021558Srgrimes struct exportlist *ep; 13031558Srgrimes struct grouplist *grp; 13041558Srgrimes{ 13051558Srgrimes struct grouplist *tgrp; 13061558Srgrimes 1307100336Sjoerg if (!(opt_flags & OP_QUIET)) 1308100336Sjoerg syslog(LOG_ERR, "bad exports list line %s", line); 13091558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 13101558Srgrimes free_exp(ep); 13111558Srgrimes while (grp) { 13121558Srgrimes tgrp = grp; 13131558Srgrimes grp = grp->gr_next; 13141558Srgrimes free_grp(tgrp); 13151558Srgrimes } 13161558Srgrimes} 13171558Srgrimes 13181558Srgrimes/* 13191558Srgrimes * Search the export list for a matching fs. 13201558Srgrimes */ 13211558Srgrimesstruct exportlist * 13221558Srgrimesex_search(fsid) 13231558Srgrimes fsid_t *fsid; 13241558Srgrimes{ 13251558Srgrimes struct exportlist *ep; 13261558Srgrimes 13271558Srgrimes ep = exphead; 13281558Srgrimes while (ep) { 13291558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 13301558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 13311558Srgrimes return (ep); 13321558Srgrimes ep = ep->ex_next; 13331558Srgrimes } 13341558Srgrimes return (ep); 13351558Srgrimes} 13361558Srgrimes 13371558Srgrimes/* 13381558Srgrimes * Add a directory path to the list. 13391558Srgrimes */ 13401558Srgrimeschar * 13411558Srgrimesadd_expdir(dpp, cp, len) 13421558Srgrimes struct dirlist **dpp; 13431558Srgrimes char *cp; 13441558Srgrimes int len; 13451558Srgrimes{ 13461558Srgrimes struct dirlist *dp; 13471558Srgrimes 13481558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 134937663Scharnier if (dp == (struct dirlist *)NULL) 135037663Scharnier out_of_mem(); 13511558Srgrimes dp->dp_left = *dpp; 13521558Srgrimes dp->dp_right = (struct dirlist *)NULL; 13531558Srgrimes dp->dp_flag = 0; 13541558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 13551558Srgrimes strcpy(dp->dp_dirp, cp); 13561558Srgrimes *dpp = dp; 13571558Srgrimes return (dp->dp_dirp); 13581558Srgrimes} 13591558Srgrimes 13601558Srgrimes/* 13611558Srgrimes * Hang the dir list element off the dirpath binary tree as required 13621558Srgrimes * and update the entry for host. 13631558Srgrimes */ 13641558Srgrimesvoid 13659336Sdfrhang_dirp(dp, grp, ep, flags) 13661558Srgrimes struct dirlist *dp; 13671558Srgrimes struct grouplist *grp; 13681558Srgrimes struct exportlist *ep; 13699336Sdfr int flags; 13701558Srgrimes{ 13711558Srgrimes struct hostlist *hp; 13721558Srgrimes struct dirlist *dp2; 13731558Srgrimes 13749336Sdfr if (flags & OP_ALLDIRS) { 13751558Srgrimes if (ep->ex_defdir) 13761558Srgrimes free((caddr_t)dp); 13771558Srgrimes else 13781558Srgrimes ep->ex_defdir = dp; 13799336Sdfr if (grp == (struct grouplist *)NULL) { 13801558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 13819336Sdfr } else while (grp) { 13821558Srgrimes hp = get_ht(); 13831558Srgrimes hp->ht_grp = grp; 13841558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 13851558Srgrimes ep->ex_defdir->dp_hosts = hp; 13861558Srgrimes grp = grp->gr_next; 13871558Srgrimes } 13881558Srgrimes } else { 13891558Srgrimes 13901558Srgrimes /* 139137663Scharnier * Loop through the directories adding them to the tree. 13921558Srgrimes */ 13931558Srgrimes while (dp) { 13941558Srgrimes dp2 = dp->dp_left; 13959336Sdfr add_dlist(&ep->ex_dirl, dp, grp, flags); 13961558Srgrimes dp = dp2; 13971558Srgrimes } 13981558Srgrimes } 13991558Srgrimes} 14001558Srgrimes 14011558Srgrimes/* 14021558Srgrimes * Traverse the binary tree either updating a node that is already there 14031558Srgrimes * for the new directory or adding the new node. 14041558Srgrimes */ 14051558Srgrimesvoid 14069336Sdfradd_dlist(dpp, newdp, grp, flags) 14071558Srgrimes struct dirlist **dpp; 14081558Srgrimes struct dirlist *newdp; 14091558Srgrimes struct grouplist *grp; 14109336Sdfr int flags; 14111558Srgrimes{ 14121558Srgrimes struct dirlist *dp; 14131558Srgrimes struct hostlist *hp; 14141558Srgrimes int cmp; 14151558Srgrimes 14161558Srgrimes dp = *dpp; 14171558Srgrimes if (dp) { 14181558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 14191558Srgrimes if (cmp > 0) { 14209336Sdfr add_dlist(&dp->dp_left, newdp, grp, flags); 14211558Srgrimes return; 14221558Srgrimes } else if (cmp < 0) { 14239336Sdfr add_dlist(&dp->dp_right, newdp, grp, flags); 14241558Srgrimes return; 14251558Srgrimes } else 14261558Srgrimes free((caddr_t)newdp); 14271558Srgrimes } else { 14281558Srgrimes dp = newdp; 14291558Srgrimes dp->dp_left = (struct dirlist *)NULL; 14301558Srgrimes *dpp = dp; 14311558Srgrimes } 14321558Srgrimes if (grp) { 14331558Srgrimes 14341558Srgrimes /* 14351558Srgrimes * Hang all of the host(s) off of the directory point. 14361558Srgrimes */ 14371558Srgrimes do { 14381558Srgrimes hp = get_ht(); 14391558Srgrimes hp->ht_grp = grp; 14401558Srgrimes hp->ht_next = dp->dp_hosts; 14411558Srgrimes dp->dp_hosts = hp; 14421558Srgrimes grp = grp->gr_next; 14431558Srgrimes } while (grp); 14449336Sdfr } else { 14451558Srgrimes dp->dp_flag |= DP_DEFSET; 14469336Sdfr } 14471558Srgrimes} 14481558Srgrimes 14491558Srgrimes/* 14501558Srgrimes * Search for a dirpath on the export point. 14511558Srgrimes */ 14521558Srgrimesstruct dirlist * 145374462Salfreddirp_search(dp, dirp) 14541558Srgrimes struct dirlist *dp; 145574462Salfred char *dirp; 14561558Srgrimes{ 14571558Srgrimes int cmp; 14581558Srgrimes 14591558Srgrimes if (dp) { 146074462Salfred cmp = strcmp(dp->dp_dirp, dirp); 14611558Srgrimes if (cmp > 0) 146274462Salfred return (dirp_search(dp->dp_left, dirp)); 14631558Srgrimes else if (cmp < 0) 146474462Salfred return (dirp_search(dp->dp_right, dirp)); 14651558Srgrimes else 14661558Srgrimes return (dp); 14671558Srgrimes } 14681558Srgrimes return (dp); 14691558Srgrimes} 14701558Srgrimes 14711558Srgrimes/* 14721558Srgrimes * Scan for a host match in a directory tree. 14731558Srgrimes */ 14741558Srgrimesint 14759336Sdfrchk_host(dp, saddr, defsetp, hostsetp) 14761558Srgrimes struct dirlist *dp; 147774462Salfred struct sockaddr *saddr; 14781558Srgrimes int *defsetp; 14799336Sdfr int *hostsetp; 14801558Srgrimes{ 14811558Srgrimes struct hostlist *hp; 14821558Srgrimes struct grouplist *grp; 148374462Salfred struct addrinfo *ai; 14841558Srgrimes 14851558Srgrimes if (dp) { 14861558Srgrimes if (dp->dp_flag & DP_DEFSET) 14879336Sdfr *defsetp = dp->dp_flag; 14881558Srgrimes hp = dp->dp_hosts; 14891558Srgrimes while (hp) { 14901558Srgrimes grp = hp->ht_grp; 14911558Srgrimes switch (grp->gr_type) { 14921558Srgrimes case GT_HOST: 149374462Salfred ai = grp->gr_ptr.gt_addrinfo; 149474462Salfred for (; ai; ai = ai->ai_next) { 149575801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 149674462Salfred *hostsetp = 149774462Salfred (hp->ht_flag | DP_HOSTSET); 149874462Salfred return (1); 149974462Salfred } 15009336Sdfr } 150175801Siedowse break; 15021558Srgrimes case GT_NET: 150375801Siedowse if (!sacmp(saddr, (struct sockaddr *) 150475801Siedowse &grp->gr_ptr.gt_net.nt_net, 150575801Siedowse (struct sockaddr *) 150675801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 150774462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 150874462Salfred return (1); 150974462Salfred } 151075801Siedowse break; 151175801Siedowse } 15121558Srgrimes hp = hp->ht_next; 15131558Srgrimes } 15141558Srgrimes } 15151558Srgrimes return (0); 15161558Srgrimes} 15171558Srgrimes 15181558Srgrimes/* 15191558Srgrimes * Scan tree for a host that matches the address. 15201558Srgrimes */ 15211558Srgrimesint 15221558Srgrimesscan_tree(dp, saddr) 15231558Srgrimes struct dirlist *dp; 152474462Salfred struct sockaddr *saddr; 15251558Srgrimes{ 15269336Sdfr int defset, hostset; 15271558Srgrimes 15281558Srgrimes if (dp) { 15291558Srgrimes if (scan_tree(dp->dp_left, saddr)) 15301558Srgrimes return (1); 15319336Sdfr if (chk_host(dp, saddr, &defset, &hostset)) 15321558Srgrimes return (1); 15331558Srgrimes if (scan_tree(dp->dp_right, saddr)) 15341558Srgrimes return (1); 15351558Srgrimes } 15361558Srgrimes return (0); 15371558Srgrimes} 15381558Srgrimes 15391558Srgrimes/* 15401558Srgrimes * Traverse the dirlist tree and free it up. 15411558Srgrimes */ 15421558Srgrimesvoid 15431558Srgrimesfree_dir(dp) 15441558Srgrimes struct dirlist *dp; 15451558Srgrimes{ 15461558Srgrimes 15471558Srgrimes if (dp) { 15481558Srgrimes free_dir(dp->dp_left); 15491558Srgrimes free_dir(dp->dp_right); 15501558Srgrimes free_host(dp->dp_hosts); 15511558Srgrimes free((caddr_t)dp); 15521558Srgrimes } 15531558Srgrimes} 15541558Srgrimes 15551558Srgrimes/* 15561558Srgrimes * Parse the option string and update fields. 15571558Srgrimes * Option arguments may either be -<option>=<value> or 15581558Srgrimes * -<option> <value> 15591558Srgrimes */ 15601558Srgrimesint 15611558Srgrimesdo_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 15621558Srgrimes char **cpp, **endcpp; 15631558Srgrimes struct exportlist *ep; 15641558Srgrimes struct grouplist *grp; 15651558Srgrimes int *has_hostp; 15661558Srgrimes int *exflagsp; 156772650Sgreen struct xucred *cr; 15681558Srgrimes{ 15691558Srgrimes char *cpoptarg, *cpoptend; 15701558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 15711558Srgrimes int allflag, usedarg; 15721558Srgrimes 157351968Salfred savedc2 = '\0'; 15741558Srgrimes cpopt = *cpp; 15751558Srgrimes cpopt++; 15761558Srgrimes cp = *endcpp; 15771558Srgrimes savedc = *cp; 15781558Srgrimes *cp = '\0'; 15791558Srgrimes while (cpopt && *cpopt) { 15801558Srgrimes allflag = 1; 15811558Srgrimes usedarg = -2; 158237663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 15831558Srgrimes *cpoptend++ = '\0'; 158437663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 15851558Srgrimes *cpoptarg++ = '\0'; 15861558Srgrimes } else { 158737663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 15881558Srgrimes *cpoptarg++ = '\0'; 15891558Srgrimes else { 15901558Srgrimes *cp = savedc; 15911558Srgrimes nextfield(&cp, &endcp); 15921558Srgrimes **endcpp = '\0'; 15931558Srgrimes if (endcp > cp && *cp != '-') { 15941558Srgrimes cpoptarg = cp; 15951558Srgrimes savedc2 = *endcp; 15961558Srgrimes *endcp = '\0'; 15971558Srgrimes usedarg = 0; 15981558Srgrimes } 15991558Srgrimes } 16001558Srgrimes } 16011558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 16021558Srgrimes *exflagsp |= MNT_EXRDONLY; 16031558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 16041558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 16051558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 16061558Srgrimes usedarg++; 16071558Srgrimes parsecred(cpoptarg, cr); 16081558Srgrimes if (allflag == 0) { 16091558Srgrimes *exflagsp |= MNT_EXPORTANON; 16101558Srgrimes opt_flags |= OP_MAPALL; 16111558Srgrimes } else 16121558Srgrimes opt_flags |= OP_MAPROOT; 16131558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 161475801Siedowse !strcmp(cpopt, "m"))) { 16151558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 161637663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 16171558Srgrimes return (1); 16181558Srgrimes } 16191558Srgrimes usedarg++; 16201558Srgrimes opt_flags |= OP_MASK; 16211558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 16221558Srgrimes !strcmp(cpopt, "n"))) { 162374462Salfred if (strchr(cpoptarg, '/') != NULL) { 162474462Salfred if (debug) 162574462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 162674462Salfred opt_flags |= OP_MASKLEN; 162774462Salfred } 16281558Srgrimes if (grp->gr_type != GT_NULL) { 162937663Scharnier syslog(LOG_ERR, "network/host conflict"); 16301558Srgrimes return (1); 16311558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 163237663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 16331558Srgrimes return (1); 16341558Srgrimes } 16351558Srgrimes grp->gr_type = GT_NET; 16361558Srgrimes *has_hostp = 1; 16371558Srgrimes usedarg++; 16381558Srgrimes opt_flags |= OP_NET; 16391558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 16401558Srgrimes opt_flags |= OP_ALLDIRS; 164127447Sdfr } else if (!strcmp(cpopt, "public")) { 164227447Sdfr *exflagsp |= MNT_EXPUBLIC; 164327447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 164427447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 164527447Sdfr opt_flags |= OP_MAPALL; 164627447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 164727447Sdfr ep->ex_indexfile = strdup(cpoptarg); 1648100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 1649100336Sjoerg opt_flags |= OP_QUIET; 16501558Srgrimes } else { 165137663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 16521558Srgrimes return (1); 16531558Srgrimes } 16541558Srgrimes if (usedarg >= 0) { 16551558Srgrimes *endcp = savedc2; 16561558Srgrimes **endcpp = savedc; 16571558Srgrimes if (usedarg > 0) { 16581558Srgrimes *cpp = cp; 16591558Srgrimes *endcpp = endcp; 16601558Srgrimes } 16611558Srgrimes return (0); 16621558Srgrimes } 16631558Srgrimes cpopt = cpoptend; 16641558Srgrimes } 16651558Srgrimes **endcpp = savedc; 16661558Srgrimes return (0); 16671558Srgrimes} 16681558Srgrimes 16691558Srgrimes/* 16701558Srgrimes * Translate a character string to the corresponding list of network 16711558Srgrimes * addresses for a hostname. 16721558Srgrimes */ 16731558Srgrimesint 16747401Swpaulget_host(cp, grp, tgrp) 16751558Srgrimes char *cp; 16761558Srgrimes struct grouplist *grp; 16777401Swpaul struct grouplist *tgrp; 16781558Srgrimes{ 16797401Swpaul struct grouplist *checkgrp; 168075635Siedowse struct addrinfo *ai, *tai, hints; 168174462Salfred int ecode; 168274462Salfred char host[NI_MAXHOST]; 16831558Srgrimes 168474462Salfred if (grp->gr_type != GT_NULL) { 168574462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 16861558Srgrimes return (1); 16871558Srgrimes } 168874462Salfred memset(&hints, 0, sizeof hints); 168974462Salfred hints.ai_flags = AI_CANONNAME; 169074462Salfred hints.ai_protocol = IPPROTO_UDP; 169174462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 169274462Salfred if (ecode != 0) { 169375635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 169474462Salfred return 1; 169574462Salfred } 169674462Salfred grp->gr_ptr.gt_addrinfo = ai; 169774462Salfred while (ai != NULL) { 169874462Salfred if (ai->ai_canonname == NULL) { 169974462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 170074462Salfred sizeof host, NULL, 0, ninumeric) != 0) 170174462Salfred strlcpy(host, "?", sizeof(host)); 170274462Salfred ai->ai_canonname = strdup(host); 170374462Salfred ai->ai_flags |= AI_CANONNAME; 170475641Siedowse } 170574462Salfred if (debug) 170675635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 170775635Siedowse /* 170875635Siedowse * Sanity check: make sure we don't already have an entry 170975635Siedowse * for this host in the grouplist. 171075635Siedowse */ 171175635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 171275635Siedowse checkgrp = checkgrp->gr_next) { 171375635Siedowse if (checkgrp->gr_type != GT_HOST) 171475635Siedowse continue; 171575635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 171675635Siedowse tai = tai->ai_next) { 171775801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 171875635Siedowse continue; 171975635Siedowse if (debug) 172075635Siedowse fprintf(stderr, 172175635Siedowse "ignoring duplicate host %s\n", 172275635Siedowse ai->ai_canonname); 172375635Siedowse grp->gr_type = GT_IGNORE; 172475635Siedowse return (0); 172575635Siedowse } 172675635Siedowse } 172774462Salfred ai = ai->ai_next; 17281558Srgrimes } 172975635Siedowse grp->gr_type = GT_HOST; 17301558Srgrimes return (0); 17311558Srgrimes} 17321558Srgrimes 17331558Srgrimes/* 17341558Srgrimes * Free up an exports list component 17351558Srgrimes */ 17361558Srgrimesvoid 17371558Srgrimesfree_exp(ep) 17381558Srgrimes struct exportlist *ep; 17391558Srgrimes{ 17401558Srgrimes 17411558Srgrimes if (ep->ex_defdir) { 17421558Srgrimes free_host(ep->ex_defdir->dp_hosts); 17431558Srgrimes free((caddr_t)ep->ex_defdir); 17441558Srgrimes } 17451558Srgrimes if (ep->ex_fsdir) 17461558Srgrimes free(ep->ex_fsdir); 174727447Sdfr if (ep->ex_indexfile) 174827447Sdfr free(ep->ex_indexfile); 17491558Srgrimes free_dir(ep->ex_dirl); 17501558Srgrimes free((caddr_t)ep); 17511558Srgrimes} 17521558Srgrimes 17531558Srgrimes/* 17541558Srgrimes * Free hosts. 17551558Srgrimes */ 17561558Srgrimesvoid 17571558Srgrimesfree_host(hp) 17581558Srgrimes struct hostlist *hp; 17591558Srgrimes{ 17601558Srgrimes struct hostlist *hp2; 17611558Srgrimes 17621558Srgrimes while (hp) { 17631558Srgrimes hp2 = hp; 17641558Srgrimes hp = hp->ht_next; 17651558Srgrimes free((caddr_t)hp2); 17661558Srgrimes } 17671558Srgrimes} 17681558Srgrimes 17691558Srgrimesstruct hostlist * 17701558Srgrimesget_ht() 17711558Srgrimes{ 17721558Srgrimes struct hostlist *hp; 17731558Srgrimes 17741558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 17751558Srgrimes if (hp == (struct hostlist *)NULL) 17761558Srgrimes out_of_mem(); 17771558Srgrimes hp->ht_next = (struct hostlist *)NULL; 17789336Sdfr hp->ht_flag = 0; 17791558Srgrimes return (hp); 17801558Srgrimes} 17811558Srgrimes 17821558Srgrimes/* 17831558Srgrimes * Out of memory, fatal 17841558Srgrimes */ 17851558Srgrimesvoid 17861558Srgrimesout_of_mem() 17871558Srgrimes{ 17881558Srgrimes 178937663Scharnier syslog(LOG_ERR, "out of memory"); 17901558Srgrimes exit(2); 17911558Srgrimes} 17921558Srgrimes 17931558Srgrimes/* 17941558Srgrimes * Do the mount syscall with the update flag to push the export info into 17951558Srgrimes * the kernel. 17961558Srgrimes */ 17971558Srgrimesint 17981558Srgrimesdo_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 17991558Srgrimes struct exportlist *ep; 18001558Srgrimes struct grouplist *grp; 18011558Srgrimes int exflags; 180272650Sgreen struct xucred *anoncrp; 18031558Srgrimes char *dirp; 18041558Srgrimes int dirplen; 18051558Srgrimes struct statfs *fsb; 18061558Srgrimes{ 180775841Siedowse struct statfs fsb1; 180874462Salfred struct addrinfo *ai; 180975801Siedowse struct export_args *eap; 181074462Salfred char *cp = NULL; 18111558Srgrimes int done; 18121558Srgrimes char savedc = '\0'; 18131558Srgrimes union { 18141558Srgrimes struct ufs_args ua; 18151558Srgrimes struct iso_args ia; 18169336Sdfr struct msdosfs_args da; 181754093Ssemenu struct ntfs_args na; 18181558Srgrimes } args; 18191558Srgrimes 182075801Siedowse bzero(&args, sizeof args); 182175801Siedowse /* XXX, we assume that all xx_args look like ufs_args. */ 18221558Srgrimes args.ua.fspec = 0; 182375801Siedowse eap = &args.ua.export; 182475801Siedowse 182575801Siedowse eap->ex_flags = exflags; 182675801Siedowse eap->ex_anon = *anoncrp; 182775801Siedowse eap->ex_indexfile = ep->ex_indexfile; 182875641Siedowse if (grp->gr_type == GT_HOST) 182974462Salfred ai = grp->gr_ptr.gt_addrinfo; 183075641Siedowse else 183175641Siedowse ai = NULL; 18321558Srgrimes done = FALSE; 18331558Srgrimes while (!done) { 18341558Srgrimes switch (grp->gr_type) { 18351558Srgrimes case GT_HOST: 183675641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 183774462Salfred goto skip; 183875801Siedowse eap->ex_addr = ai->ai_addr; 183975801Siedowse eap->ex_addrlen = ai->ai_addrlen; 184075801Siedowse eap->ex_masklen = 0; 18411558Srgrimes break; 18421558Srgrimes case GT_NET: 184375801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 184474462Salfred have_v6 == 0) 184574462Salfred goto skip; 184675801Siedowse eap->ex_addr = 184775801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 184875801Siedowse eap->ex_addrlen = args.ua.export.ex_addr->sa_len; 184975801Siedowse eap->ex_mask = 185075801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 185175801Siedowse eap->ex_masklen = args.ua.export.ex_mask->sa_len; 18521558Srgrimes break; 185375641Siedowse case GT_DEFAULT: 185475801Siedowse eap->ex_addr = NULL; 185575801Siedowse eap->ex_addrlen = 0; 185675801Siedowse eap->ex_mask = NULL; 185775801Siedowse eap->ex_masklen = 0; 185875641Siedowse break; 18597401Swpaul case GT_IGNORE: 18607401Swpaul return(0); 18617401Swpaul break; 18621558Srgrimes default: 186337663Scharnier syslog(LOG_ERR, "bad grouptype"); 18641558Srgrimes if (cp) 18651558Srgrimes *cp = savedc; 18661558Srgrimes return (1); 18671558Srgrimes }; 18681558Srgrimes 18691558Srgrimes /* 18701558Srgrimes * XXX: 18711558Srgrimes * Maybe I should just use the fsb->f_mntonname path instead 18721558Srgrimes * of looping back up the dirp to the mount point?? 18731558Srgrimes * Also, needs to know how to export all types of local 187496707Strhodes * exportable filesystems and not just "ufs". 18751558Srgrimes */ 18769336Sdfr while (mount(fsb->f_fstypename, dirp, 187774462Salfred fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 18781558Srgrimes if (cp) 18791558Srgrimes *cp-- = savedc; 18801558Srgrimes else 18811558Srgrimes cp = dirp + dirplen - 1; 1882100336Sjoerg if (opt_flags & OP_QUIET) 1883100336Sjoerg return (1); 18841558Srgrimes if (errno == EPERM) { 188575635Siedowse if (debug) 188675635Siedowse warnx("can't change attributes for %s", 188775635Siedowse dirp); 18881558Srgrimes syslog(LOG_ERR, 188937663Scharnier "can't change attributes for %s", dirp); 18901558Srgrimes return (1); 18911558Srgrimes } 18921558Srgrimes if (opt_flags & OP_ALLDIRS) { 1893100336Sjoerg if (errno == EINVAL) 1894100336Sjoerg syslog(LOG_ERR, 1895100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 1896100336Sjoerg dirp); 1897100336Sjoerg else 1898100336Sjoerg syslog(LOG_ERR, 1899100336Sjoerg "could not remount %s: %m", 1900100336Sjoerg dirp); 19011558Srgrimes return (1); 19021558Srgrimes } 19031558Srgrimes /* back up over the last component */ 19041558Srgrimes while (*cp == '/' && cp > dirp) 19051558Srgrimes cp--; 19061558Srgrimes while (*(cp - 1) != '/' && cp > dirp) 19071558Srgrimes cp--; 19081558Srgrimes if (cp == dirp) { 19091558Srgrimes if (debug) 191037663Scharnier warnx("mnt unsucc"); 191137663Scharnier syslog(LOG_ERR, "can't export %s", dirp); 19121558Srgrimes return (1); 19131558Srgrimes } 19141558Srgrimes savedc = *cp; 19151558Srgrimes *cp = '\0'; 191675841Siedowse /* Check that we're still on the same filesystem. */ 191775841Siedowse if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid, 191875841Siedowse &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) { 191975841Siedowse *cp = savedc; 192075841Siedowse syslog(LOG_ERR, "can't export %s", dirp); 192175841Siedowse return (1); 192275841Siedowse } 19231558Srgrimes } 192474462Salfredskip: 192575641Siedowse if (ai != NULL) 192674462Salfred ai = ai->ai_next; 192775641Siedowse if (ai == NULL) 19281558Srgrimes done = TRUE; 19291558Srgrimes } 19301558Srgrimes if (cp) 19311558Srgrimes *cp = savedc; 19321558Srgrimes return (0); 19331558Srgrimes} 19341558Srgrimes 19351558Srgrimes/* 19361558Srgrimes * Translate a net address. 193775801Siedowse * 193875801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 19391558Srgrimes */ 19401558Srgrimesint 19411558Srgrimesget_net(cp, net, maskflg) 19421558Srgrimes char *cp; 19431558Srgrimes struct netmsk *net; 19441558Srgrimes int maskflg; 19451558Srgrimes{ 194675861Siedowse struct netent *np = NULL; 194774462Salfred char *name, *p, *prefp; 194875801Siedowse struct sockaddr_in sin; 194975861Siedowse struct sockaddr *sa = NULL; 195074462Salfred struct addrinfo hints, *ai = NULL; 195174462Salfred char netname[NI_MAXHOST]; 195274462Salfred long preflen; 19531558Srgrimes 195475635Siedowse p = prefp = NULL; 195574462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 195674462Salfred p = strchr(cp, '/'); 195774462Salfred *p = '\0'; 195874462Salfred prefp = p + 1; 195974462Salfred } 196074462Salfred 196175861Siedowse /* 196275861Siedowse * Check for a numeric address first. We wish to avoid 196375861Siedowse * possible DNS lookups in getnetbyname(). 196475861Siedowse */ 196575861Siedowse if (isxdigit(*cp) || *cp == ':') { 196674462Salfred memset(&hints, 0, sizeof hints); 196775801Siedowse /* Ensure the mask and the network have the same family. */ 196875801Siedowse if (maskflg && (opt_flags & OP_NET)) 196975801Siedowse hints.ai_family = net->nt_net.ss_family; 197075801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 197175801Siedowse hints.ai_family = net->nt_mask.ss_family; 197275801Siedowse else 197375801Siedowse hints.ai_family = AF_UNSPEC; 197474462Salfred hints.ai_flags = AI_NUMERICHOST; 197575861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 197675861Siedowse sa = ai->ai_addr; 197775861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 197874462Salfred /* 197975801Siedowse * The address in `cp' is really a network address, so 198075801Siedowse * use inet_network() to re-interpret this correctly. 198175801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 198274462Salfred */ 198375801Siedowse bzero(&sin, sizeof sin); 198474462Salfred sin.sin_family = AF_INET; 198574462Salfred sin.sin_len = sizeof sin; 198675801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 198774462Salfred if (debug) 198875801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 198975801Siedowse inet_ntoa(sin.sin_addr)); 199074462Salfred sa = (struct sockaddr *)&sin; 199175861Siedowse } 199275861Siedowse } 199375861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 199475861Siedowse bzero(&sin, sizeof sin); 199575861Siedowse sin.sin_family = AF_INET; 199675861Siedowse sin.sin_len = sizeof sin; 199775861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 199875861Siedowse sa = (struct sockaddr *)&sin; 199975861Siedowse } 200075861Siedowse if (sa == NULL) 200174462Salfred goto fail; 200225318Spst 200375801Siedowse if (maskflg) { 200475801Siedowse /* The specified sockaddr is a mask. */ 200575801Siedowse if (checkmask(sa) != 0) 200675801Siedowse goto fail; 200775801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 200875801Siedowse opt_flags |= OP_HAVEMASK; 200975801Siedowse } else { 201075801Siedowse /* The specified sockaddr is a network address. */ 201175801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 201274462Salfred 201375801Siedowse /* Get a network name for the export list. */ 201475801Siedowse if (np) { 201575801Siedowse name = np->n_name; 201675801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 201775801Siedowse NULL, 0, ninumeric) == 0) { 201875801Siedowse name = netname; 201975801Siedowse } else { 202075801Siedowse goto fail; 202175801Siedowse } 202275801Siedowse if ((net->nt_name = strdup(name)) == NULL) 202375801Siedowse out_of_mem(); 202475801Siedowse 202575801Siedowse /* 202675801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 202775801Siedowse * from the class of an IPv4 address. 202875801Siedowse */ 202974462Salfred if (opt_flags & OP_MASKLEN) { 203074462Salfred preflen = strtol(prefp, NULL, 10); 203175801Siedowse if (preflen < 0L || preflen == LONG_MAX) 203274462Salfred goto fail; 203375801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 203475801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 203575801Siedowse goto fail; 203675801Siedowse opt_flags |= OP_HAVEMASK; 203774462Salfred *p = '/'; 203875801Siedowse } else if (sa->sa_family == AF_INET && 203975801Siedowse (opt_flags & OP_MASK) == 0) { 204075801Siedowse in_addr_t addr; 204174462Salfred 204275801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 204375801Siedowse if (IN_CLASSA(addr)) 204475801Siedowse preflen = 8; 204575801Siedowse else if (IN_CLASSB(addr)) 204675801Siedowse preflen = 16; 204775801Siedowse else if (IN_CLASSC(addr)) 204875801Siedowse preflen = 24; 204975801Siedowse else if (IN_CLASSD(addr)) 205075801Siedowse preflen = 28; 205175801Siedowse else 205275801Siedowse preflen = 32; /* XXX */ 205375801Siedowse 205475801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 205575801Siedowse makemask(&net->nt_mask, (int)preflen); 205675801Siedowse opt_flags |= OP_HAVEMASK; 205774462Salfred } 205874462Salfred } 205974462Salfred 206074462Salfred if (ai) 206174462Salfred freeaddrinfo(ai); 206274462Salfred return 0; 206374462Salfred 206474462Salfredfail: 206574462Salfred if (ai) 206674462Salfred freeaddrinfo(ai); 206774462Salfred return 1; 20681558Srgrimes} 20691558Srgrimes 20701558Srgrimes/* 20711558Srgrimes * Parse out the next white space separated field 20721558Srgrimes */ 20731558Srgrimesvoid 20741558Srgrimesnextfield(cp, endcp) 20751558Srgrimes char **cp; 20761558Srgrimes char **endcp; 20771558Srgrimes{ 20781558Srgrimes char *p; 20791558Srgrimes 20801558Srgrimes p = *cp; 20811558Srgrimes while (*p == ' ' || *p == '\t') 20821558Srgrimes p++; 20831558Srgrimes if (*p == '\n' || *p == '\0') 20841558Srgrimes *cp = *endcp = p; 20851558Srgrimes else { 20861558Srgrimes *cp = p++; 20871558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 20881558Srgrimes p++; 20891558Srgrimes *endcp = p; 20901558Srgrimes } 20911558Srgrimes} 20921558Srgrimes 20931558Srgrimes/* 20941558Srgrimes * Get an exports file line. Skip over blank lines and handle line 20951558Srgrimes * continuations. 20961558Srgrimes */ 20971558Srgrimesint 20981558Srgrimesget_line() 20991558Srgrimes{ 21001558Srgrimes char *p, *cp; 210196622Siedowse size_t len; 21021558Srgrimes int totlen, cont_line; 21031558Srgrimes 21041558Srgrimes /* 21051558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 21061558Srgrimes */ 21071558Srgrimes p = line; 21081558Srgrimes totlen = 0; 21091558Srgrimes do { 211096622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 21111558Srgrimes return (0); 21121558Srgrimes cp = p + len - 1; 21131558Srgrimes cont_line = 0; 21141558Srgrimes while (cp >= p && 21151558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 21161558Srgrimes if (*cp == '\\') 21171558Srgrimes cont_line = 1; 21181558Srgrimes cp--; 21191558Srgrimes len--; 21201558Srgrimes } 212179117Sdd if (cont_line) { 212279117Sdd *++cp = ' '; 212379117Sdd len++; 212479117Sdd } 212596622Siedowse if (linesize < len + totlen + 1) { 212696622Siedowse linesize = len + totlen + 1; 212796622Siedowse line = realloc(line, linesize); 212896622Siedowse if (line == NULL) 212996622Siedowse out_of_mem(); 21301558Srgrimes } 213196622Siedowse memcpy(line + totlen, p, len); 213296622Siedowse totlen += len; 213396622Siedowse line[totlen] = '\0'; 21341558Srgrimes } while (totlen == 0 || cont_line); 21351558Srgrimes return (1); 21361558Srgrimes} 21371558Srgrimes 21381558Srgrimes/* 21391558Srgrimes * Parse a description of a credential. 21401558Srgrimes */ 21411558Srgrimesvoid 21421558Srgrimesparsecred(namelist, cr) 21431558Srgrimes char *namelist; 214472650Sgreen struct xucred *cr; 21451558Srgrimes{ 21461558Srgrimes char *name; 21471558Srgrimes int cnt; 21481558Srgrimes char *names; 21491558Srgrimes struct passwd *pw; 21501558Srgrimes struct group *gr; 21511558Srgrimes int ngroups, groups[NGROUPS + 1]; 21521558Srgrimes 215391354Sdd cr->cr_version = XUCRED_VERSION; 21541558Srgrimes /* 215537663Scharnier * Set up the unprivileged user. 21561558Srgrimes */ 21571558Srgrimes cr->cr_uid = -2; 21581558Srgrimes cr->cr_groups[0] = -2; 21591558Srgrimes cr->cr_ngroups = 1; 21601558Srgrimes /* 21611558Srgrimes * Get the user's password table entry. 21621558Srgrimes */ 21631558Srgrimes names = strsep(&namelist, " \t\n"); 21641558Srgrimes name = strsep(&names, ":"); 21651558Srgrimes if (isdigit(*name) || *name == '-') 21661558Srgrimes pw = getpwuid(atoi(name)); 21671558Srgrimes else 21681558Srgrimes pw = getpwnam(name); 21691558Srgrimes /* 21701558Srgrimes * Credentials specified as those of a user. 21711558Srgrimes */ 21721558Srgrimes if (names == NULL) { 21731558Srgrimes if (pw == NULL) { 217437663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 21751558Srgrimes return; 21761558Srgrimes } 21771558Srgrimes cr->cr_uid = pw->pw_uid; 21781558Srgrimes ngroups = NGROUPS + 1; 21791558Srgrimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 218037663Scharnier syslog(LOG_ERR, "too many groups"); 21811558Srgrimes /* 21821558Srgrimes * Convert from int's to gid_t's and compress out duplicate 21831558Srgrimes */ 21841558Srgrimes cr->cr_ngroups = ngroups - 1; 21851558Srgrimes cr->cr_groups[0] = groups[0]; 21861558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 21871558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 21881558Srgrimes return; 21891558Srgrimes } 21901558Srgrimes /* 21911558Srgrimes * Explicit credential specified as a colon separated list: 21921558Srgrimes * uid:gid:gid:... 21931558Srgrimes */ 21941558Srgrimes if (pw != NULL) 21951558Srgrimes cr->cr_uid = pw->pw_uid; 21961558Srgrimes else if (isdigit(*name) || *name == '-') 21971558Srgrimes cr->cr_uid = atoi(name); 21981558Srgrimes else { 219937663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 22001558Srgrimes return; 22011558Srgrimes } 22021558Srgrimes cr->cr_ngroups = 0; 22031558Srgrimes while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 22041558Srgrimes name = strsep(&names, ":"); 22051558Srgrimes if (isdigit(*name) || *name == '-') { 22061558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 22071558Srgrimes } else { 22081558Srgrimes if ((gr = getgrnam(name)) == NULL) { 220937663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 22101558Srgrimes continue; 22111558Srgrimes } 22121558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 22131558Srgrimes } 22141558Srgrimes } 22151558Srgrimes if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 221637663Scharnier syslog(LOG_ERR, "too many groups"); 22171558Srgrimes} 22181558Srgrimes 22191558Srgrimes#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 22201558Srgrimes/* 22211558Srgrimes * Routines that maintain the remote mounttab 22221558Srgrimes */ 22231558Srgrimesvoid 22241558Srgrimesget_mountlist() 22251558Srgrimes{ 22261558Srgrimes struct mountlist *mlp, **mlpp; 222723681Speter char *host, *dirp, *cp; 22281558Srgrimes char str[STRSIZ]; 22291558Srgrimes FILE *mlfile; 22301558Srgrimes 22311558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 223253117Sbillf if (errno == ENOENT) 223353117Sbillf return; 223453117Sbillf else { 223553117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 223653117Sbillf return; 223753117Sbillf } 22381558Srgrimes } 22391558Srgrimes mlpp = &mlhead; 22401558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 224123681Speter cp = str; 224223681Speter host = strsep(&cp, " \t\n"); 224323681Speter dirp = strsep(&cp, " \t\n"); 224423681Speter if (host == NULL || dirp == NULL) 22451558Srgrimes continue; 22461558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 224737663Scharnier if (mlp == (struct mountlist *)NULL) 224837663Scharnier out_of_mem(); 224923681Speter strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 225023681Speter mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 225123681Speter strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 225223681Speter mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 22531558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 22541558Srgrimes *mlpp = mlp; 22551558Srgrimes mlpp = &mlp->ml_next; 22561558Srgrimes } 22571558Srgrimes fclose(mlfile); 22581558Srgrimes} 22591558Srgrimes 226075635Siedowsevoid 226175635Siedowsedel_mlist(char *hostp, char *dirp) 22621558Srgrimes{ 22631558Srgrimes struct mountlist *mlp, **mlpp; 22641558Srgrimes struct mountlist *mlp2; 22651558Srgrimes FILE *mlfile; 22661558Srgrimes int fnd = 0; 22671558Srgrimes 22681558Srgrimes mlpp = &mlhead; 22691558Srgrimes mlp = mlhead; 22701558Srgrimes while (mlp) { 22711558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 22721558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 22731558Srgrimes fnd = 1; 22741558Srgrimes mlp2 = mlp; 22751558Srgrimes *mlpp = mlp = mlp->ml_next; 22761558Srgrimes free((caddr_t)mlp2); 22771558Srgrimes } else { 22781558Srgrimes mlpp = &mlp->ml_next; 22791558Srgrimes mlp = mlp->ml_next; 22801558Srgrimes } 22811558Srgrimes } 22821558Srgrimes if (fnd) { 22831558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 228437663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 22851558Srgrimes return; 22861558Srgrimes } 22871558Srgrimes mlp = mlhead; 22881558Srgrimes while (mlp) { 22891558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 22901558Srgrimes mlp = mlp->ml_next; 22911558Srgrimes } 22921558Srgrimes fclose(mlfile); 22931558Srgrimes } 22941558Srgrimes} 22951558Srgrimes 22961558Srgrimesvoid 22971558Srgrimesadd_mlist(hostp, dirp) 22981558Srgrimes char *hostp, *dirp; 22991558Srgrimes{ 23001558Srgrimes struct mountlist *mlp, **mlpp; 23011558Srgrimes FILE *mlfile; 23021558Srgrimes 23031558Srgrimes mlpp = &mlhead; 23041558Srgrimes mlp = mlhead; 23051558Srgrimes while (mlp) { 23061558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 23071558Srgrimes return; 23081558Srgrimes mlpp = &mlp->ml_next; 23091558Srgrimes mlp = mlp->ml_next; 23101558Srgrimes } 23111558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 231237663Scharnier if (mlp == (struct mountlist *)NULL) 231337663Scharnier out_of_mem(); 23141558Srgrimes strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 23151558Srgrimes mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 23161558Srgrimes strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 23171558Srgrimes mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 23181558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 23191558Srgrimes *mlpp = mlp; 23201558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 232137663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 23221558Srgrimes return; 23231558Srgrimes } 23241558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 23251558Srgrimes fclose(mlfile); 23261558Srgrimes} 23271558Srgrimes 23281558Srgrimes/* 23291558Srgrimes * Free up a group list. 23301558Srgrimes */ 23311558Srgrimesvoid 23321558Srgrimesfree_grp(grp) 23331558Srgrimes struct grouplist *grp; 23341558Srgrimes{ 23351558Srgrimes if (grp->gr_type == GT_HOST) { 233674462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 233774462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 23381558Srgrimes } else if (grp->gr_type == GT_NET) { 23391558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 23401558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 23411558Srgrimes } 23421558Srgrimes free((caddr_t)grp); 23431558Srgrimes} 23441558Srgrimes 23451558Srgrimes#ifdef DEBUG 23461558Srgrimesvoid 23471558SrgrimesSYSLOG(int pri, const char *fmt, ...) 23481558Srgrimes{ 23491558Srgrimes va_list ap; 23501558Srgrimes 23511558Srgrimes va_start(ap, fmt); 23521558Srgrimes vfprintf(stderr, fmt, ap); 23531558Srgrimes va_end(ap); 23541558Srgrimes} 23551558Srgrimes#endif /* DEBUG */ 23561558Srgrimes 23571558Srgrimes/* 23581558Srgrimes * Check options for consistency. 23591558Srgrimes */ 23601558Srgrimesint 23611558Srgrimescheck_options(dp) 23621558Srgrimes struct dirlist *dp; 23631558Srgrimes{ 23641558Srgrimes 23651558Srgrimes if (dp == (struct dirlist *)NULL) 23661558Srgrimes return (1); 236783653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 236883653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 23691558Srgrimes return (1); 23701558Srgrimes } 23711558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 237275801Siedowse syslog(LOG_ERR, "-mask requires -network"); 237375801Siedowse return (1); 23741558Srgrimes } 237575801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 237675801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 237775801Siedowse return (1); 237875801Siedowse } 237975801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 238075801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 238175801Siedowse return (1); 238275801Siedowse } 23831558Srgrimes if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 238445927Salex syslog(LOG_ERR, "-alldirs has multiple directories"); 23851558Srgrimes return (1); 23861558Srgrimes } 23871558Srgrimes return (0); 23881558Srgrimes} 23891558Srgrimes 23901558Srgrimes/* 23911558Srgrimes * Check an absolute directory path for any symbolic links. Return true 23921558Srgrimes */ 23931558Srgrimesint 23941558Srgrimescheck_dirpath(dirp) 23951558Srgrimes char *dirp; 23961558Srgrimes{ 23971558Srgrimes char *cp; 23981558Srgrimes int ret = 1; 23991558Srgrimes struct stat sb; 24001558Srgrimes 24011558Srgrimes cp = dirp + 1; 24021558Srgrimes while (*cp && ret) { 24031558Srgrimes if (*cp == '/') { 24041558Srgrimes *cp = '\0'; 24059336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 24061558Srgrimes ret = 0; 24071558Srgrimes *cp = '/'; 24081558Srgrimes } 24091558Srgrimes cp++; 24101558Srgrimes } 24119336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 24121558Srgrimes ret = 0; 24131558Srgrimes return (ret); 24141558Srgrimes} 24159336Sdfr 241675801Siedowse/* 241775801Siedowse * Make a netmask according to the specified prefix length. The ss_family 241875801Siedowse * and other non-address fields must be initialised before calling this. 241975801Siedowse */ 242075801Siedowseint 242175801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 242274462Salfred{ 242375801Siedowse u_char *p; 242475801Siedowse int bits, i, len; 242574462Salfred 242675801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 242775801Siedowse return (-1); 2428103949Smike if (bitlen > len * CHAR_BIT) 242975801Siedowse return (-1); 243074462Salfred 243175801Siedowse for (i = 0; i < len; i++) { 2432103949Smike bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 243375801Siedowse *p++ = (1 << bits) - 1; 243475801Siedowse bitlen -= bits; 243574462Salfred } 243675801Siedowse return 0; 243774462Salfred} 243874462Salfred 243975801Siedowse/* 244075801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 244175801Siedowse * is acceptable (i.e. of the form 1...10....0). 244275801Siedowse */ 244375801Siedowseint 244475801Siedowsecheckmask(struct sockaddr *sa) 244574462Salfred{ 244675801Siedowse u_char *mask; 244775801Siedowse int i, len; 244874462Salfred 244975801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 245075801Siedowse return (-1); 245175801Siedowse 245275801Siedowse for (i = 0; i < len; i++) 245375801Siedowse if (mask[i] != 0xff) 245475801Siedowse break; 245575801Siedowse if (i < len) { 245675801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 245775801Siedowse return (-1); 245875801Siedowse i++; 245974462Salfred } 246075801Siedowse for (; i < len; i++) 246175801Siedowse if (mask[i] != 0) 246275801Siedowse return (-1); 246375801Siedowse return (0); 246474462Salfred} 246574462Salfred 246675801Siedowse/* 246775801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 246875801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 246975801Siedowse * If samask is NULL, perform a full comparision. 247075801Siedowse */ 247175801Siedowseint 247275801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 247374462Salfred{ 247475801Siedowse unsigned char *p1, *p2, *mask; 247575801Siedowse int len, i; 247674462Salfred 247775801Siedowse if (sa1->sa_family != sa2->sa_family || 247875801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 247975801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 248075801Siedowse return (1); 248175801Siedowse 248275801Siedowse switch (sa1->sa_family) { 248374462Salfred case AF_INET6: 248475801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 248575801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 248675801Siedowse return (1); 248774462Salfred break; 248874462Salfred } 248974462Salfred 249075801Siedowse /* Simple binary comparison if no mask specified. */ 249175801Siedowse if (samask == NULL) 249275801Siedowse return (memcmp(p1, p2, len)); 249374462Salfred 249475801Siedowse /* Set up the mask, and do a mask-based comparison. */ 249575801Siedowse if (sa1->sa_family != samask->sa_family || 249675801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 249775801Siedowse return (1); 249874462Salfred 249975801Siedowse for (i = 0; i < len; i++) 250075801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 250175801Siedowse return (1); 250275801Siedowse return (0); 250374462Salfred} 250474462Salfred 250575801Siedowse/* 250675801Siedowse * Return a pointer to the part of the sockaddr that contains the 250775801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 250875801Siedowse * NULL if the address family is unknown. 250975801Siedowse */ 251075801Siedowsevoid * 251175801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 251275801Siedowse void *p; 251374462Salfred int len; 251474462Salfred 251575801Siedowse switch (sa->sa_family) { 251674462Salfred case AF_INET: 251775801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 251875801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 251974462Salfred break; 252074462Salfred case AF_INET6: 252175801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 252275801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 252374462Salfred break; 252474462Salfred default: 252575801Siedowse p = NULL; 252675801Siedowse len = 0; 252774462Salfred } 252874462Salfred 252975801Siedowse if (nbytes != NULL) 253075801Siedowse *nbytes = len; 253175801Siedowse return (p); 253274462Salfred} 253374462Salfred 253475754Siedowsevoid 253575754Siedowsehuphandler(int sig) 253675754Siedowse{ 253775754Siedowse got_sighup = 1; 253875754Siedowse} 253975754Siedowse 254074462Salfredvoid terminate(sig) 254174462Salfredint sig; 254274462Salfred{ 254374462Salfred close(mountdlockfd); 254474462Salfred unlink(MOUNTDLOCK); 254574792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 254674792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 254774462Salfred exit (0); 254874462Salfred} 2549