mountd.c revision 146187
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1989, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * This code is derived from software contributed to Berkeley by 61558Srgrimes * Herb Hasler and Rick Macklem at The University of Guelph. 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 4. Neither the name of the University nor the names of its contributors 171558Srgrimes * may be used to endorse or promote products derived from this software 181558Srgrimes * without specific prior written permission. 191558Srgrimes * 201558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301558Srgrimes * SUCH DAMAGE. 311558Srgrimes */ 321558Srgrimes 331558Srgrimes#ifndef lint 3437663Scharnierstatic const char copyright[] = 351558Srgrimes"@(#) Copyright (c) 1989, 1993\n\ 361558Srgrimes The Regents of the University of California. All rights reserved.\n"; 372999Swollman#endif /*not lint*/ 381558Srgrimes 39105267Scharnier#if 0 401558Srgrimes#ifndef lint 4137663Scharnierstatic char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 42105267Scharnier#endif /*not lint*/ 4337663Scharnier#endif 441558Srgrimes 45105267Scharnier#include <sys/cdefs.h> 46105267Scharnier__FBSDID("$FreeBSD: head/usr.sbin/mountd/mountd.c 146187 2005-05-13 16:31:11Z ume $"); 47105267Scharnier 481558Srgrimes#include <sys/param.h> 491558Srgrimes#include <sys/mount.h> 5074462Salfred#include <sys/fcntl.h> 511558Srgrimes#include <sys/stat.h> 521558Srgrimes#include <sys/syslog.h> 5324330Sguido#include <sys/sysctl.h> 5496622Siedowse#include <sys/linker.h> 5596622Siedowse#include <sys/module.h> 561558Srgrimes 571558Srgrimes#include <rpc/rpc.h> 58109363Smbr#include <rpc/rpc_com.h> 591558Srgrimes#include <rpc/pmap_clnt.h> 6074462Salfred#include <rpc/pmap_prot.h> 6174462Salfred#include <rpcsvc/mount.h> 621558Srgrimes#include <nfs/rpcv2.h> 639336Sdfr#include <nfs/nfsproto.h> 6483653Speter#include <nfsserver/nfs.h> 6523681Speter#include <ufs/ufs/ufsmount.h> 6677162Sru#include <fs/msdosfs/msdosfsmount.h> 6777223Sru#include <fs/ntfs/ntfsmount.h> 6823681Speter#include <isofs/cd9660/cd9660_mount.h> /* XXX need isofs in include */ 691558Srgrimes 701558Srgrimes#include <arpa/inet.h> 711558Srgrimes 721558Srgrimes#include <ctype.h> 7337663Scharnier#include <err.h> 741558Srgrimes#include <errno.h> 751558Srgrimes#include <grp.h> 76103949Smike#include <limits.h> 771558Srgrimes#include <netdb.h> 781558Srgrimes#include <pwd.h> 791558Srgrimes#include <signal.h> 801558Srgrimes#include <stdio.h> 811558Srgrimes#include <stdlib.h> 821558Srgrimes#include <string.h> 831558Srgrimes#include <unistd.h> 841558Srgrimes#include "pathnames.h" 851558Srgrimes 861558Srgrimes#ifdef DEBUG 871558Srgrimes#include <stdarg.h> 881558Srgrimes#endif 891558Srgrimes 9074462Salfred#ifndef MOUNTDLOCK 9174462Salfred#define MOUNTDLOCK "/var/run/mountd.lock" 9274462Salfred#endif 9374462Salfred 941558Srgrimes/* 951558Srgrimes * Structures for keeping the mount list and export list 961558Srgrimes */ 971558Srgrimesstruct mountlist { 981558Srgrimes struct mountlist *ml_next; 991558Srgrimes char ml_host[RPCMNT_NAMELEN+1]; 1001558Srgrimes char ml_dirp[RPCMNT_PATHLEN+1]; 1011558Srgrimes}; 1021558Srgrimes 1031558Srgrimesstruct dirlist { 1041558Srgrimes struct dirlist *dp_left; 1051558Srgrimes struct dirlist *dp_right; 1061558Srgrimes int dp_flag; 1071558Srgrimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 1081558Srgrimes char dp_dirp[1]; /* Actually malloc'd to size of dir */ 1091558Srgrimes}; 1101558Srgrimes/* dp_flag bits */ 1111558Srgrimes#define DP_DEFSET 0x1 1129336Sdfr#define DP_HOSTSET 0x2 1131558Srgrimes 1141558Srgrimesstruct exportlist { 1151558Srgrimes struct exportlist *ex_next; 1161558Srgrimes struct dirlist *ex_dirl; 1171558Srgrimes struct dirlist *ex_defdir; 1181558Srgrimes int ex_flag; 1191558Srgrimes fsid_t ex_fs; 1201558Srgrimes char *ex_fsdir; 12127447Sdfr char *ex_indexfile; 1221558Srgrimes}; 1231558Srgrimes/* ex_flag bits */ 1241558Srgrimes#define EX_LINKED 0x1 1251558Srgrimes 1261558Srgrimesstruct netmsk { 12774462Salfred struct sockaddr_storage nt_net; 12875801Siedowse struct sockaddr_storage nt_mask; 12942144Sdfr char *nt_name; 1301558Srgrimes}; 1311558Srgrimes 1321558Srgrimesunion grouptypes { 13374462Salfred struct addrinfo *gt_addrinfo; 1341558Srgrimes struct netmsk gt_net; 1351558Srgrimes}; 1361558Srgrimes 1371558Srgrimesstruct grouplist { 1381558Srgrimes int gr_type; 1391558Srgrimes union grouptypes gr_ptr; 1401558Srgrimes struct grouplist *gr_next; 1411558Srgrimes}; 1421558Srgrimes/* Group types */ 1431558Srgrimes#define GT_NULL 0x0 1441558Srgrimes#define GT_HOST 0x1 1451558Srgrimes#define GT_NET 0x2 14675641Siedowse#define GT_DEFAULT 0x3 1477401Swpaul#define GT_IGNORE 0x5 1481558Srgrimes 1491558Srgrimesstruct hostlist { 1509336Sdfr int ht_flag; /* Uses DP_xx bits */ 1511558Srgrimes struct grouplist *ht_grp; 1521558Srgrimes struct hostlist *ht_next; 1531558Srgrimes}; 1541558Srgrimes 1559336Sdfrstruct fhreturn { 1569336Sdfr int fhr_flag; 1579336Sdfr int fhr_vers; 1589336Sdfr nfsfh_t fhr_fh; 1599336Sdfr}; 1609336Sdfr 1611558Srgrimes/* Global defs */ 16292882Simpchar *add_expdir(struct dirlist **, char *, int); 16392882Simpvoid add_dlist(struct dirlist **, struct dirlist *, 16492882Simp struct grouplist *, int); 16592882Simpvoid add_mlist(char *, char *); 16692882Simpint check_dirpath(char *); 16792882Simpint check_options(struct dirlist *); 16875801Siedowseint checkmask(struct sockaddr *sa); 16992882Simpint chk_host(struct dirlist *, struct sockaddr *, int *, int *); 17075635Siedowsevoid del_mlist(char *hostp, char *dirp); 17192882Simpstruct dirlist *dirp_search(struct dirlist *, char *); 17292882Simpint do_mount(struct exportlist *, struct grouplist *, int, 17392882Simp struct xucred *, char *, int, struct statfs *); 17492882Simpint do_opt(char **, char **, struct exportlist *, struct grouplist *, 17592882Simp int *, int *, struct xucred *); 17692882Simpstruct exportlist *ex_search(fsid_t *); 17792882Simpstruct exportlist *get_exp(void); 17892882Simpvoid free_dir(struct dirlist *); 17992882Simpvoid free_exp(struct exportlist *); 18092882Simpvoid free_grp(struct grouplist *); 18192882Simpvoid free_host(struct hostlist *); 18292882Simpvoid get_exportlist(void); 18392882Simpint get_host(char *, struct grouplist *, struct grouplist *); 18492882Simpstruct hostlist *get_ht(void); 18592882Simpint get_line(void); 18692882Simpvoid get_mountlist(void); 18792882Simpint get_net(char *, struct netmsk *, int); 18892882Simpvoid getexp_err(struct exportlist *, struct grouplist *); 18992882Simpstruct grouplist *get_grp(void); 19092882Simpvoid hang_dirp(struct dirlist *, struct grouplist *, 19192882Simp struct exportlist *, int); 19275754Siedowsevoid huphandler(int sig); 19375801Siedowseint makemask(struct sockaddr_storage *ssp, int bitlen); 19492882Simpvoid mntsrv(struct svc_req *, SVCXPRT *); 19592882Simpvoid nextfield(char **, char **); 19692882Simpvoid out_of_mem(void); 19792882Simpvoid parsecred(char *, struct xucred *); 198100117Salfredint put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 19975801Siedowsevoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 20075801Siedowseint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 20175801Siedowse struct sockaddr *samask); 20292882Simpint scan_tree(struct dirlist *, struct sockaddr *); 20392882Simpstatic void usage(void); 20492882Simpint xdr_dir(XDR *, char *); 20592882Simpint xdr_explist(XDR *, caddr_t); 206100117Salfredint xdr_explist_brief(XDR *, caddr_t); 20792882Simpint xdr_fhs(XDR *, caddr_t); 20892882Simpint xdr_mlist(XDR *, caddr_t); 20992882Simpvoid terminate(int); 2101558Srgrimes 2111558Srgrimesstruct exportlist *exphead; 2121558Srgrimesstruct mountlist *mlhead; 2131558Srgrimesstruct grouplist *grphead; 2141558Srgrimeschar exname[MAXPATHLEN]; 21572650Sgreenstruct xucred def_anon = { 21691354Sdd XUCRED_VERSION, 21772650Sgreen (uid_t)-2, 2181558Srgrimes 1, 21972650Sgreen { (gid_t)-2 }, 22072650Sgreen NULL 2211558Srgrimes}; 22225087Sdfrint force_v2 = 0; 2239336Sdfrint resvport_only = 1; 2249336Sdfrint dir_only = 1; 225121767Speterint dolog = 0; 22675754Siedowseint got_sighup = 0; 22774462Salfred 2281558Srgrimesint opt_flags; 22974462Salfredstatic int have_v6 = 1; 23074462Salfred 23174462Salfredint mountdlockfd; 23275801Siedowse/* Bits for opt_flags above */ 2331558Srgrimes#define OP_MAPROOT 0x01 2341558Srgrimes#define OP_MAPALL 0x02 23583653Speter/* 0x4 free */ 2361558Srgrimes#define OP_MASK 0x08 2371558Srgrimes#define OP_NET 0x10 2381558Srgrimes#define OP_ALLDIRS 0x40 23975801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 240100336Sjoerg#define OP_QUIET 0x100 24174462Salfred#define OP_MASKLEN 0x200 2421558Srgrimes 2431558Srgrimes#ifdef DEBUG 2441558Srgrimesint debug = 1; 24592882Simpvoid SYSLOG(int, const char *, ...) __printflike(2, 3); 2461558Srgrimes#define syslog SYSLOG 2471558Srgrimes#else 2481558Srgrimesint debug = 0; 2491558Srgrimes#endif 2501558Srgrimes 2511558Srgrimes/* 2521558Srgrimes * Mountd server for NFS mount protocol as described in: 2531558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 2541558Srgrimes * The optional arguments are the exports file name 2551558Srgrimes * default: _PATH_EXPORTS 2561558Srgrimes * and "-n" to allow nonroot mount. 2571558Srgrimes */ 2581558Srgrimesint 2591558Srgrimesmain(argc, argv) 2601558Srgrimes int argc; 2611558Srgrimes char **argv; 2621558Srgrimes{ 26375754Siedowse fd_set readfds; 264126572Sbms struct sockaddr_in sin; 265126572Sbms struct sockaddr_in6 sin6; 266126572Sbms char *endptr; 26774462Salfred SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; 26874462Salfred struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 26974462Salfred int udpsock, tcpsock, udp6sock, tcp6sock; 27074462Salfred int xcreated = 0, s; 271109363Smbr int maxrec = RPC_MAXDATASIZE; 27274462Salfred int one = 1; 273126572Sbms int c, r; 274126572Sbms in_port_t svcport = 0; 2751558Srgrimes 27675635Siedowse udp6conf = tcp6conf = NULL; 277126643Smarkm udp6sock = tcp6sock = 0; 27875635Siedowse 27974462Salfred /* Check that another mountd isn't already running. */ 28074462Salfred if ((mountdlockfd = (open(MOUNTDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) 28174462Salfred err(1, "%s", MOUNTDLOCK); 28274462Salfred 28374462Salfred if(flock(mountdlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) 284105267Scharnier errx(1, "another mountd is already running. Aborting"); 28574462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 28674462Salfred if (s < 0) 28774462Salfred have_v6 = 0; 28874462Salfred else 28974462Salfred close(s); 29083687Speter if (modfind("nfsserver") < 0) { 29183687Speter /* Not present in kernel, try loading it */ 29283687Speter if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 29383687Speter errx(1, "NFS server is not available or loadable"); 2942999Swollman } 2952999Swollman 296126572Sbms while ((c = getopt(argc, argv, "2dlnp:r")) != -1) 2971558Srgrimes switch (c) { 29825087Sdfr case '2': 29925087Sdfr force_v2 = 1; 30025087Sdfr break; 3019336Sdfr case 'n': 3029336Sdfr resvport_only = 0; 3039336Sdfr break; 3049336Sdfr case 'r': 3059336Sdfr dir_only = 0; 3069336Sdfr break; 3078688Sphk case 'd': 3088688Sphk debug = debug ? 0 : 1; 3098688Sphk break; 31031656Sguido case 'l': 311121767Speter dolog = 1; 31231656Sguido break; 313126572Sbms case 'p': 314126572Sbms endptr = NULL; 315126572Sbms svcport = (in_port_t)strtoul(optarg, &endptr, 10); 316126572Sbms if (endptr == NULL || *endptr != '\0' || 317126572Sbms svcport == 0 || svcport >= IPPORT_MAX) 318126572Sbms usage(); 319126572Sbms break; 3201558Srgrimes default: 32137663Scharnier usage(); 3221558Srgrimes }; 3231558Srgrimes argc -= optind; 3241558Srgrimes argv += optind; 3251558Srgrimes grphead = (struct grouplist *)NULL; 3261558Srgrimes exphead = (struct exportlist *)NULL; 3271558Srgrimes mlhead = (struct mountlist *)NULL; 3281558Srgrimes if (argc == 1) { 3291558Srgrimes strncpy(exname, *argv, MAXPATHLEN-1); 3301558Srgrimes exname[MAXPATHLEN-1] = '\0'; 3311558Srgrimes } else 3321558Srgrimes strcpy(exname, _PATH_EXPORTS); 3331558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 3341558Srgrimes if (debug) 33537663Scharnier warnx("getting export list"); 3361558Srgrimes get_exportlist(); 3371558Srgrimes if (debug) 33837663Scharnier warnx("getting mount list"); 3391558Srgrimes get_mountlist(); 3401558Srgrimes if (debug) 34137663Scharnier warnx("here we go"); 3421558Srgrimes if (debug == 0) { 3431558Srgrimes daemon(0, 0); 3441558Srgrimes signal(SIGINT, SIG_IGN); 3451558Srgrimes signal(SIGQUIT, SIG_IGN); 3461558Srgrimes } 34775754Siedowse signal(SIGHUP, huphandler); 34874462Salfred signal(SIGTERM, terminate); 3491558Srgrimes { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 3501558Srgrimes if (pidfile != NULL) { 3511558Srgrimes fprintf(pidfile, "%d\n", getpid()); 3521558Srgrimes fclose(pidfile); 3531558Srgrimes } 3541558Srgrimes } 35574462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 35674462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 35774462Salfred udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 35874462Salfred tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 35974791Salfred udpconf = getnetconfigent("udp"); 36074791Salfred tcpconf = getnetconfigent("tcp"); 361109363Smbr 362109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 363109363Smbr 36474791Salfred if (!have_v6) 36574791Salfred goto skip_v6; 36674462Salfred udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 36774462Salfred tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 36874462Salfred /* 36974462Salfred * We're doing host-based access checks here, so don't allow 37074462Salfred * v4-in-v6 to confuse things. The kernel will disable it 37174462Salfred * by default on NFS sockets too. 37274462Salfred */ 37374462Salfred if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6, 374117684Srwatson IPV6_V6ONLY, &one, sizeof one) < 0) { 37574462Salfred syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 37674462Salfred exit(1); 37774462Salfred } 37874462Salfred if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6, 379117684Srwatson IPV6_V6ONLY, &one, sizeof one) < 0) { 380117684Srwatson syslog(LOG_ERR, "can't disable v4-in-v6 on TCP socket"); 38174462Salfred exit(1); 38274462Salfred } 38374462Salfred udp6conf = getnetconfigent("udp6"); 38474462Salfred tcp6conf = getnetconfigent("tcp6"); 38574791Salfred 38674791Salfredskip_v6: 38724759Sguido if (!resvport_only) { 38883687Speter if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 38983687Speter &resvport_only, sizeof(resvport_only)) != 0 && 39083687Speter errno != ENOENT) { 39124759Sguido syslog(LOG_ERR, "sysctl: %m"); 39224759Sguido exit(1); 39324759Sguido } 39424330Sguido } 395126572Sbms if (svcport != 0) { 396126572Sbms bzero(&sin, sizeof(struct sockaddr_in)); 397126572Sbms sin.sin_len = sizeof(struct sockaddr_in); 398126572Sbms sin.sin_family = AF_INET; 399126572Sbms sin.sin_port = htons(svcport); 400126572Sbms 401126572Sbms bzero(&sin6, sizeof(struct sockaddr_in6)); 402126572Sbms sin6.sin6_len = sizeof(struct sockaddr_in6); 403126572Sbms sin6.sin6_family = AF_INET6; 404126572Sbms sin6.sin6_port = htons(svcport); 405126572Sbms } 40674462Salfred if (udpsock != -1 && udpconf != NULL) { 407126572Sbms if (svcport != 0) { 408126572Sbms r = bindresvport(udpsock, &sin); 409126572Sbms if (r != 0) { 410126572Sbms syslog(LOG_ERR, "bindresvport: %m"); 411126572Sbms exit(1); 412126572Sbms } 413126572Sbms } else 414126572Sbms (void)bindresvport(udpsock, NULL); 41574462Salfred udptransp = svc_dg_create(udpsock, 0, 0); 41674462Salfred if (udptransp != NULL) { 41774462Salfred if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, 41874462Salfred mntsrv, udpconf)) 41974462Salfred syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service"); 42074462Salfred else 42174462Salfred xcreated++; 42274462Salfred if (!force_v2) { 42374462Salfred if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3, 42474462Salfred mntsrv, udpconf)) 42574462Salfred syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service"); 42674462Salfred else 42774462Salfred xcreated++; 42874462Salfred } 42974462Salfred } else 43074462Salfred syslog(LOG_WARNING, "can't create UDP services"); 43174462Salfred 43274462Salfred } 43374462Salfred if (tcpsock != -1 && tcpconf != NULL) { 434126572Sbms if (svcport != 0) { 435126572Sbms r = bindresvport(tcpsock, &sin); 436126572Sbms if (r != 0) { 437126572Sbms syslog(LOG_ERR, "bindresvport: %m"); 438126572Sbms exit(1); 439126572Sbms } 440126572Sbms } else 441126572Sbms (void)bindresvport(tcpsock, NULL); 44274462Salfred listen(tcpsock, SOMAXCONN); 443109363Smbr tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 44474462Salfred if (tcptransp != NULL) { 44574462Salfred if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1, 44674462Salfred mntsrv, tcpconf)) 44774462Salfred syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service"); 44874462Salfred else 44974462Salfred xcreated++; 45074462Salfred if (!force_v2) { 45174462Salfred if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3, 45274462Salfred mntsrv, tcpconf)) 45374462Salfred syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service"); 45474462Salfred else 45574462Salfred xcreated++; 45674462Salfred } 45774462Salfred } else 45874462Salfred syslog(LOG_WARNING, "can't create TCP service"); 45974462Salfred 46074462Salfred } 46174791Salfred if (have_v6 && udp6sock != -1 && udp6conf != NULL) { 462126572Sbms if (svcport != 0) { 463126572Sbms r = bindresvport_sa(udp6sock, 464126572Sbms (struct sockaddr *)&sin6); 465126572Sbms if (r != 0) { 466126572Sbms syslog(LOG_ERR, "bindresvport_sa: %m"); 467126572Sbms exit(1); 468126572Sbms } 469126572Sbms } else 470126572Sbms (void)bindresvport_sa(udp6sock, NULL); 47174462Salfred udp6transp = svc_dg_create(udp6sock, 0, 0); 47274462Salfred if (udp6transp != NULL) { 47374462Salfred if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, 47474462Salfred mntsrv, udp6conf)) 47574462Salfred syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service"); 47674462Salfred else 47774462Salfred xcreated++; 47874462Salfred if (!force_v2) { 47974462Salfred if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3, 48074462Salfred mntsrv, udp6conf)) 48174462Salfred syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service"); 48274462Salfred else 48374462Salfred xcreated++; 48474462Salfred } 48574462Salfred } else 48674462Salfred syslog(LOG_WARNING, "can't create UDP6 service"); 48774462Salfred 48874462Salfred } 48974791Salfred if (have_v6 && tcp6sock != -1 && tcp6conf != NULL) { 490126572Sbms if (svcport != 0) { 491126572Sbms r = bindresvport_sa(tcp6sock, 492126572Sbms (struct sockaddr *)&sin6); 493126572Sbms if (r != 0) { 494126572Sbms syslog(LOG_ERR, "bindresvport_sa: %m"); 495126572Sbms exit(1); 496126572Sbms } 497126572Sbms } else 498126572Sbms (void)bindresvport_sa(tcp6sock, NULL); 49974462Salfred listen(tcp6sock, SOMAXCONN); 500109363Smbr tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 50174462Salfred if (tcp6transp != NULL) { 50274462Salfred if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1, 50374462Salfred mntsrv, tcp6conf)) 50474462Salfred syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service"); 50574462Salfred else 50674462Salfred xcreated++; 50774462Salfred if (!force_v2) { 50874462Salfred if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3, 50974462Salfred mntsrv, tcp6conf)) 51074462Salfred syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service"); 51174462Salfred else 51274462Salfred xcreated++; 51374462Salfred } 51474462Salfred } else 51574462Salfred syslog(LOG_WARNING, "can't create TCP6 service"); 51674462Salfred 51774462Salfred } 51874462Salfred if (xcreated == 0) { 51974462Salfred syslog(LOG_ERR, "could not create any services"); 5201558Srgrimes exit(1); 5211558Srgrimes } 52275754Siedowse 52375754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 52475754Siedowse for (;;) { 52575754Siedowse if (got_sighup) { 52675754Siedowse get_exportlist(); 52775754Siedowse got_sighup = 0; 52875754Siedowse } 52975754Siedowse readfds = svc_fdset; 53075754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 53175754Siedowse case -1: 53275754Siedowse if (errno == EINTR) 53375754Siedowse continue; 53475754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 53575754Siedowse exit(1); 53675754Siedowse case 0: 53775754Siedowse continue; 53875754Siedowse default: 53975754Siedowse svc_getreqset(&readfds); 54075754Siedowse } 54175754Siedowse } 5421558Srgrimes} 5431558Srgrimes 54437663Scharnierstatic void 54537663Scharnierusage() 54637663Scharnier{ 54737663Scharnier fprintf(stderr, 548126572Sbms "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] " 549126572Sbms "[export_file]\n"); 55037663Scharnier exit(1); 55137663Scharnier} 55237663Scharnier 5531558Srgrimes/* 5541558Srgrimes * The mount rpc service 5551558Srgrimes */ 5561558Srgrimesvoid 5571558Srgrimesmntsrv(rqstp, transp) 5581558Srgrimes struct svc_req *rqstp; 5591558Srgrimes SVCXPRT *transp; 5601558Srgrimes{ 5611558Srgrimes struct exportlist *ep; 5621558Srgrimes struct dirlist *dp; 5639336Sdfr struct fhreturn fhr; 5641558Srgrimes struct stat stb; 5651558Srgrimes struct statfs fsb; 56674462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 56774462Salfred int lookup_failed = 1; 56874462Salfred struct sockaddr *saddr; 5699336Sdfr u_short sport; 57023681Speter char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 57128911Sguido int bad = 0, defset, hostset; 5729336Sdfr sigset_t sighup_mask; 5731558Srgrimes 5749336Sdfr sigemptyset(&sighup_mask); 5759336Sdfr sigaddset(&sighup_mask, SIGHUP); 57674462Salfred saddr = svc_getrpccaller(transp)->buf; 57774462Salfred switch (saddr->sa_family) { 57874462Salfred case AF_INET6: 57975635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 58074462Salfred break; 58174462Salfred case AF_INET: 58275635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 58374462Salfred break; 58474462Salfred default: 58574462Salfred syslog(LOG_ERR, "request from unknown address family"); 58674462Salfred return; 58774462Salfred } 58874462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 58974462Salfred NULL, 0, 0); 59074462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 59174462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 5921558Srgrimes switch (rqstp->rq_proc) { 5931558Srgrimes case NULLPROC: 594121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 59537663Scharnier syslog(LOG_ERR, "can't send reply"); 5961558Srgrimes return; 5971558Srgrimes case RPCMNT_MOUNT: 5989336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 59931656Sguido syslog(LOG_NOTICE, 60031656Sguido "mount request from %s from unprivileged port", 60174462Salfred numerichost); 6021558Srgrimes svcerr_weakauth(transp); 6031558Srgrimes return; 6041558Srgrimes } 605121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 60631656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 60774462Salfred numerichost); 6081558Srgrimes svcerr_decode(transp); 6091558Srgrimes return; 6101558Srgrimes } 6111558Srgrimes 6121558Srgrimes /* 6131558Srgrimes * Get the real pathname and make sure it is a directory 6149336Sdfr * or a regular file if the -r option was specified 6159336Sdfr * and it exists. 6161558Srgrimes */ 61751968Salfred if (realpath(rpcpath, dirpath) == NULL || 6181558Srgrimes stat(dirpath, &stb) < 0 || 6199336Sdfr (!S_ISDIR(stb.st_mode) && 62074462Salfred (dir_only || !S_ISREG(stb.st_mode))) || 6211558Srgrimes statfs(dirpath, &fsb) < 0) { 6221558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 62331656Sguido syslog(LOG_NOTICE, 62437663Scharnier "mount request from %s for non existent path %s", 62574462Salfred numerichost, dirpath); 6261558Srgrimes if (debug) 62737663Scharnier warnx("stat failed on %s", dirpath); 62828911Sguido bad = ENOENT; /* We will send error reply later */ 6291558Srgrimes } 6301558Srgrimes 6311558Srgrimes /* Check in the exports list */ 6329336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 6331558Srgrimes ep = ex_search(&fsb.f_fsid); 6349336Sdfr hostset = defset = 0; 6359336Sdfr if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 6361558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 63774462Salfred chk_host(dp, saddr, &defset, &hostset)) || 63874462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 63974462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 64028911Sguido if (bad) { 641121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 64228911Sguido (caddr_t)&bad)) 64337663Scharnier syslog(LOG_ERR, "can't send reply"); 64428911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 64528911Sguido return; 64628911Sguido } 6479336Sdfr if (hostset & DP_HOSTSET) 6489336Sdfr fhr.fhr_flag = hostset; 6499336Sdfr else 6509336Sdfr fhr.fhr_flag = defset; 6519336Sdfr fhr.fhr_vers = rqstp->rq_vers; 6521558Srgrimes /* Get the file handle */ 65323681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 6549336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 6551558Srgrimes bad = errno; 65637663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 657121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 6581558Srgrimes (caddr_t)&bad)) 65937663Scharnier syslog(LOG_ERR, "can't send reply"); 6609336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 6611558Srgrimes return; 6621558Srgrimes } 663121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 664121556Speter (caddr_t)&fhr)) 66537663Scharnier syslog(LOG_ERR, "can't send reply"); 66674462Salfred if (!lookup_failed) 66774462Salfred add_mlist(host, dirpath); 6681558Srgrimes else 66974462Salfred add_mlist(numerichost, dirpath); 6701558Srgrimes if (debug) 67137663Scharnier warnx("mount successful"); 672121767Speter if (dolog) 67331656Sguido syslog(LOG_NOTICE, 67431656Sguido "mount request succeeded from %s for %s", 67574462Salfred numerichost, dirpath); 67631656Sguido } else { 6771558Srgrimes bad = EACCES; 67831656Sguido syslog(LOG_NOTICE, 67931656Sguido "mount request denied from %s for %s", 68074462Salfred numerichost, dirpath); 68131656Sguido } 68228911Sguido 683121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 684121556Speter (caddr_t)&bad)) 68537663Scharnier syslog(LOG_ERR, "can't send reply"); 6869336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 6871558Srgrimes return; 6881558Srgrimes case RPCMNT_DUMP: 689121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 69037663Scharnier syslog(LOG_ERR, "can't send reply"); 691121767Speter else if (dolog) 69231656Sguido syslog(LOG_NOTICE, 69331656Sguido "dump request succeeded from %s", 69474462Salfred numerichost); 6951558Srgrimes return; 6961558Srgrimes case RPCMNT_UMOUNT: 6979336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 69831656Sguido syslog(LOG_NOTICE, 69931656Sguido "umount request from %s from unprivileged port", 70074462Salfred numerichost); 7011558Srgrimes svcerr_weakauth(transp); 7021558Srgrimes return; 7031558Srgrimes } 704121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 70531656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 70674462Salfred numerichost); 7071558Srgrimes svcerr_decode(transp); 7081558Srgrimes return; 7091558Srgrimes } 71051968Salfred if (realpath(rpcpath, dirpath) == NULL) { 71151968Salfred syslog(LOG_NOTICE, "umount request from %s " 71251968Salfred "for non existent path %s", 71374462Salfred numerichost, dirpath); 71451968Salfred } 715121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 71637663Scharnier syslog(LOG_ERR, "can't send reply"); 71774462Salfred if (!lookup_failed) 71875635Siedowse del_mlist(host, dirpath); 71975635Siedowse del_mlist(numerichost, dirpath); 720121767Speter if (dolog) 72131656Sguido syslog(LOG_NOTICE, 72231656Sguido "umount request succeeded from %s for %s", 72374462Salfred numerichost, dirpath); 7241558Srgrimes return; 7251558Srgrimes case RPCMNT_UMNTALL: 7269336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 72731656Sguido syslog(LOG_NOTICE, 72831656Sguido "umountall request from %s from unprivileged port", 72974462Salfred numerichost); 7301558Srgrimes svcerr_weakauth(transp); 7311558Srgrimes return; 7321558Srgrimes } 733121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 73437663Scharnier syslog(LOG_ERR, "can't send reply"); 73574462Salfred if (!lookup_failed) 73675635Siedowse del_mlist(host, NULL); 73775635Siedowse del_mlist(numerichost, NULL); 738121767Speter if (dolog) 73931656Sguido syslog(LOG_NOTICE, 74031656Sguido "umountall request succeeded from %s", 74174462Salfred numerichost); 7421558Srgrimes return; 7431558Srgrimes case RPCMNT_EXPORT: 744121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 745121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 746121556Speter (caddr_t)NULL)) 747100117Salfred syslog(LOG_ERR, "can't send reply"); 748121767Speter if (dolog) 74931656Sguido syslog(LOG_NOTICE, 75031656Sguido "export request succeeded from %s", 75174462Salfred numerichost); 7521558Srgrimes return; 7531558Srgrimes default: 7541558Srgrimes svcerr_noproc(transp); 7551558Srgrimes return; 7561558Srgrimes } 7571558Srgrimes} 7581558Srgrimes 7591558Srgrimes/* 7601558Srgrimes * Xdr conversion for a dirpath string 7611558Srgrimes */ 7621558Srgrimesint 7631558Srgrimesxdr_dir(xdrsp, dirp) 7641558Srgrimes XDR *xdrsp; 7651558Srgrimes char *dirp; 7661558Srgrimes{ 7671558Srgrimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 7681558Srgrimes} 7691558Srgrimes 7701558Srgrimes/* 7719336Sdfr * Xdr routine to generate file handle reply 7721558Srgrimes */ 7731558Srgrimesint 7749336Sdfrxdr_fhs(xdrsp, cp) 7751558Srgrimes XDR *xdrsp; 7769336Sdfr caddr_t cp; 7771558Srgrimes{ 77892806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 7799336Sdfr u_long ok = 0, len, auth; 7801558Srgrimes 7811558Srgrimes if (!xdr_long(xdrsp, &ok)) 7821558Srgrimes return (0); 7839336Sdfr switch (fhrp->fhr_vers) { 7849336Sdfr case 1: 7859336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 7869336Sdfr case 3: 7879336Sdfr len = NFSX_V3FH; 7889336Sdfr if (!xdr_long(xdrsp, &len)) 7899336Sdfr return (0); 7909336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 7919336Sdfr return (0); 79283653Speter auth = RPCAUTH_UNIX; 7939336Sdfr len = 1; 7949336Sdfr if (!xdr_long(xdrsp, &len)) 7959336Sdfr return (0); 7969336Sdfr return (xdr_long(xdrsp, &auth)); 7979336Sdfr }; 7989336Sdfr return (0); 7991558Srgrimes} 8001558Srgrimes 8011558Srgrimesint 8021558Srgrimesxdr_mlist(xdrsp, cp) 8031558Srgrimes XDR *xdrsp; 8041558Srgrimes caddr_t cp; 8051558Srgrimes{ 8061558Srgrimes struct mountlist *mlp; 8071558Srgrimes int true = 1; 8081558Srgrimes int false = 0; 8091558Srgrimes char *strp; 8101558Srgrimes 8111558Srgrimes mlp = mlhead; 8121558Srgrimes while (mlp) { 8131558Srgrimes if (!xdr_bool(xdrsp, &true)) 8141558Srgrimes return (0); 8151558Srgrimes strp = &mlp->ml_host[0]; 8161558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 8171558Srgrimes return (0); 8181558Srgrimes strp = &mlp->ml_dirp[0]; 8191558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 8201558Srgrimes return (0); 8211558Srgrimes mlp = mlp->ml_next; 8221558Srgrimes } 8231558Srgrimes if (!xdr_bool(xdrsp, &false)) 8241558Srgrimes return (0); 8251558Srgrimes return (1); 8261558Srgrimes} 8271558Srgrimes 8281558Srgrimes/* 8291558Srgrimes * Xdr conversion for export list 8301558Srgrimes */ 8311558Srgrimesint 832100117Salfredxdr_explist_common(xdrsp, cp, brief) 8331558Srgrimes XDR *xdrsp; 8341558Srgrimes caddr_t cp; 835100117Salfred int brief; 8361558Srgrimes{ 8371558Srgrimes struct exportlist *ep; 8381558Srgrimes int false = 0; 8399336Sdfr int putdef; 8409336Sdfr sigset_t sighup_mask; 8411558Srgrimes 8429336Sdfr sigemptyset(&sighup_mask); 8439336Sdfr sigaddset(&sighup_mask, SIGHUP); 8449336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 8451558Srgrimes ep = exphead; 8461558Srgrimes while (ep) { 8471558Srgrimes putdef = 0; 848100117Salfred if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 849100117Salfred &putdef, brief)) 8501558Srgrimes goto errout; 8511558Srgrimes if (ep->ex_defdir && putdef == 0 && 8521558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 853100117Salfred &putdef, brief)) 8541558Srgrimes goto errout; 8551558Srgrimes ep = ep->ex_next; 8561558Srgrimes } 8579336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8581558Srgrimes if (!xdr_bool(xdrsp, &false)) 8591558Srgrimes return (0); 8601558Srgrimes return (1); 8611558Srgrimeserrout: 8629336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8631558Srgrimes return (0); 8641558Srgrimes} 8651558Srgrimes 8661558Srgrimes/* 8671558Srgrimes * Called from xdr_explist() to traverse the tree and export the 8681558Srgrimes * directory paths. 8691558Srgrimes */ 8701558Srgrimesint 871100117Salfredput_exlist(dp, xdrsp, adp, putdefp, brief) 8721558Srgrimes struct dirlist *dp; 8731558Srgrimes XDR *xdrsp; 8741558Srgrimes struct dirlist *adp; 8751558Srgrimes int *putdefp; 876100117Salfred int brief; 8771558Srgrimes{ 8781558Srgrimes struct grouplist *grp; 8791558Srgrimes struct hostlist *hp; 8801558Srgrimes int true = 1; 8811558Srgrimes int false = 0; 8821558Srgrimes int gotalldir = 0; 8831558Srgrimes char *strp; 8841558Srgrimes 8851558Srgrimes if (dp) { 886100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 8871558Srgrimes return (1); 8881558Srgrimes if (!xdr_bool(xdrsp, &true)) 8891558Srgrimes return (1); 8901558Srgrimes strp = dp->dp_dirp; 8911558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 8921558Srgrimes return (1); 8931558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 8941558Srgrimes gotalldir = 1; 8951558Srgrimes *putdefp = 1; 8961558Srgrimes } 897100117Salfred if (brief) { 898100117Salfred if (!xdr_bool(xdrsp, &true)) 899100117Salfred return (1); 900100117Salfred strp = "(...)"; 901100117Salfred if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 902100117Salfred return (1); 903100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 9041558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 9051558Srgrimes hp = dp->dp_hosts; 9061558Srgrimes while (hp) { 9071558Srgrimes grp = hp->ht_grp; 9081558Srgrimes if (grp->gr_type == GT_HOST) { 9091558Srgrimes if (!xdr_bool(xdrsp, &true)) 9101558Srgrimes return (1); 91174462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 9128871Srgrimes if (!xdr_string(xdrsp, &strp, 9131558Srgrimes RPCMNT_NAMELEN)) 9141558Srgrimes return (1); 9151558Srgrimes } else if (grp->gr_type == GT_NET) { 9161558Srgrimes if (!xdr_bool(xdrsp, &true)) 9171558Srgrimes return (1); 9181558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 9198871Srgrimes if (!xdr_string(xdrsp, &strp, 9201558Srgrimes RPCMNT_NAMELEN)) 9211558Srgrimes return (1); 9221558Srgrimes } 9231558Srgrimes hp = hp->ht_next; 9241558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 9251558Srgrimes hp = adp->dp_hosts; 9261558Srgrimes gotalldir = 0; 9271558Srgrimes } 9281558Srgrimes } 9291558Srgrimes } 9301558Srgrimes if (!xdr_bool(xdrsp, &false)) 9311558Srgrimes return (1); 932100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 9331558Srgrimes return (1); 9341558Srgrimes } 9351558Srgrimes return (0); 9361558Srgrimes} 9371558Srgrimes 938100117Salfredint 939100117Salfredxdr_explist(xdrsp, cp) 940100117Salfred XDR *xdrsp; 941100117Salfred caddr_t cp; 942100117Salfred{ 943100117Salfred 944100117Salfred return xdr_explist_common(xdrsp, cp, 0); 945100117Salfred} 946100117Salfred 947100117Salfredint 948100117Salfredxdr_explist_brief(xdrsp, cp) 949100117Salfred XDR *xdrsp; 950100117Salfred caddr_t cp; 951100117Salfred{ 952100117Salfred 953100117Salfred return xdr_explist_common(xdrsp, cp, 1); 954100117Salfred} 955100117Salfred 95696622Siedowsechar *line; 95796622Siedowseint linesize; 9581558SrgrimesFILE *exp_file; 9591558Srgrimes 9601558Srgrimes/* 9611558Srgrimes * Get the export list 9621558Srgrimes */ 9631558Srgrimesvoid 9641558Srgrimesget_exportlist() 9651558Srgrimes{ 9661558Srgrimes struct exportlist *ep, *ep2; 9671558Srgrimes struct grouplist *grp, *tgrp; 9681558Srgrimes struct exportlist **epp; 9691558Srgrimes struct dirlist *dirhead; 9701558Srgrimes struct statfs fsb, *fsp; 97172650Sgreen struct xucred anon; 9721558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 9731558Srgrimes int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 9741558Srgrimes 97551968Salfred dirp = NULL; 97651968Salfred dirplen = 0; 97751968Salfred 9781558Srgrimes /* 9791558Srgrimes * First, get rid of the old list 9801558Srgrimes */ 9811558Srgrimes ep = exphead; 9821558Srgrimes while (ep) { 9831558Srgrimes ep2 = ep; 9841558Srgrimes ep = ep->ex_next; 9851558Srgrimes free_exp(ep2); 9861558Srgrimes } 9871558Srgrimes exphead = (struct exportlist *)NULL; 9881558Srgrimes 9891558Srgrimes grp = grphead; 9901558Srgrimes while (grp) { 9911558Srgrimes tgrp = grp; 9921558Srgrimes grp = grp->gr_next; 9931558Srgrimes free_grp(tgrp); 9941558Srgrimes } 9951558Srgrimes grphead = (struct grouplist *)NULL; 9961558Srgrimes 9971558Srgrimes /* 9981558Srgrimes * And delete exports that are in the kernel for all local 99996707Strhodes * filesystems. 100096707Strhodes * XXX: Should know how to handle all local exportable filesystems 100123681Speter * instead of just "ufs". 10021558Srgrimes */ 10031558Srgrimes num = getmntinfo(&fsp, MNT_NOWAIT); 10041558Srgrimes for (i = 0; i < num; i++) { 10051558Srgrimes union { 10061558Srgrimes struct ufs_args ua; 10071558Srgrimes struct iso_args ia; 10089336Sdfr struct msdosfs_args da; 100954093Ssemenu struct ntfs_args na; 10101558Srgrimes } targs; 10111558Srgrimes 101277435Sphk if (!strcmp(fsp->f_fstypename, "ufs") || 101377577Sru !strcmp(fsp->f_fstypename, "msdosfs") || 101454093Ssemenu !strcmp(fsp->f_fstypename, "ntfs") || 101523681Speter !strcmp(fsp->f_fstypename, "cd9660")) { 1016138680Sphk bzero(&targs, sizeof targs); 10179336Sdfr targs.ua.fspec = NULL; 10189336Sdfr targs.ua.export.ex_flags = MNT_DELEXPORT; 10199336Sdfr if (mount(fsp->f_fstypename, fsp->f_mntonname, 102077405Siedowse fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0 && 102177405Siedowse errno != ENOENT) 102277405Siedowse syslog(LOG_ERR, 102377405Siedowse "can't delete exports for %s: %m", 102474462Salfred fsp->f_mntonname); 10251558Srgrimes } 10261558Srgrimes fsp++; 10271558Srgrimes } 10281558Srgrimes 10291558Srgrimes /* 10301558Srgrimes * Read in the exports file and build the list, calling 10311558Srgrimes * mount() as we go along to push the export rules into the kernel. 10321558Srgrimes */ 10331558Srgrimes if ((exp_file = fopen(exname, "r")) == NULL) { 103437663Scharnier syslog(LOG_ERR, "can't open %s", exname); 10351558Srgrimes exit(2); 10361558Srgrimes } 10371558Srgrimes dirhead = (struct dirlist *)NULL; 10381558Srgrimes while (get_line()) { 10391558Srgrimes if (debug) 104037663Scharnier warnx("got line %s", line); 10411558Srgrimes cp = line; 10421558Srgrimes nextfield(&cp, &endcp); 10431558Srgrimes if (*cp == '#') 10441558Srgrimes goto nextline; 10451558Srgrimes 10461558Srgrimes /* 10471558Srgrimes * Set defaults. 10481558Srgrimes */ 10491558Srgrimes has_host = FALSE; 10501558Srgrimes anon = def_anon; 10511558Srgrimes exflags = MNT_EXPORTED; 10521558Srgrimes got_nondir = 0; 10531558Srgrimes opt_flags = 0; 10541558Srgrimes ep = (struct exportlist *)NULL; 10551558Srgrimes 10561558Srgrimes /* 10571558Srgrimes * Create new exports list entry 10581558Srgrimes */ 10591558Srgrimes len = endcp-cp; 10601558Srgrimes tgrp = grp = get_grp(); 10611558Srgrimes while (len > 0) { 10621558Srgrimes if (len > RPCMNT_NAMELEN) { 10631558Srgrimes getexp_err(ep, tgrp); 10641558Srgrimes goto nextline; 10651558Srgrimes } 10661558Srgrimes if (*cp == '-') { 10671558Srgrimes if (ep == (struct exportlist *)NULL) { 10681558Srgrimes getexp_err(ep, tgrp); 10691558Srgrimes goto nextline; 10701558Srgrimes } 10711558Srgrimes if (debug) 107237663Scharnier warnx("doing opt %s", cp); 10731558Srgrimes got_nondir = 1; 10741558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 10751558Srgrimes &exflags, &anon)) { 10761558Srgrimes getexp_err(ep, tgrp); 10771558Srgrimes goto nextline; 10781558Srgrimes } 10791558Srgrimes } else if (*cp == '/') { 10801558Srgrimes savedc = *endcp; 10811558Srgrimes *endcp = '\0'; 10821558Srgrimes if (check_dirpath(cp) && 10831558Srgrimes statfs(cp, &fsb) >= 0) { 10841558Srgrimes if (got_nondir) { 108537663Scharnier syslog(LOG_ERR, "dirs must be first"); 10861558Srgrimes getexp_err(ep, tgrp); 10871558Srgrimes goto nextline; 10881558Srgrimes } 10891558Srgrimes if (ep) { 10901558Srgrimes if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 10911558Srgrimes ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 10921558Srgrimes getexp_err(ep, tgrp); 10931558Srgrimes goto nextline; 10941558Srgrimes } 10951558Srgrimes } else { 10961558Srgrimes /* 10971558Srgrimes * See if this directory is already 10981558Srgrimes * in the list. 10991558Srgrimes */ 11001558Srgrimes ep = ex_search(&fsb.f_fsid); 11011558Srgrimes if (ep == (struct exportlist *)NULL) { 11021558Srgrimes ep = get_exp(); 11031558Srgrimes ep->ex_fs = fsb.f_fsid; 11041558Srgrimes ep->ex_fsdir = (char *) 11051558Srgrimes malloc(strlen(fsb.f_mntonname) + 1); 11061558Srgrimes if (ep->ex_fsdir) 11071558Srgrimes strcpy(ep->ex_fsdir, 11081558Srgrimes fsb.f_mntonname); 11091558Srgrimes else 11101558Srgrimes out_of_mem(); 11111558Srgrimes if (debug) 111274462Salfred warnx("making new ep fs=0x%x,0x%x", 111374462Salfred fsb.f_fsid.val[0], 111474462Salfred fsb.f_fsid.val[1]); 11151558Srgrimes } else if (debug) 111637663Scharnier warnx("found ep fs=0x%x,0x%x", 11171558Srgrimes fsb.f_fsid.val[0], 11181558Srgrimes fsb.f_fsid.val[1]); 11191558Srgrimes } 11201558Srgrimes 11211558Srgrimes /* 11221558Srgrimes * Add dirpath to export mount point. 11231558Srgrimes */ 11241558Srgrimes dirp = add_expdir(&dirhead, cp, len); 11251558Srgrimes dirplen = len; 11261558Srgrimes } else { 11271558Srgrimes getexp_err(ep, tgrp); 11281558Srgrimes goto nextline; 11291558Srgrimes } 11301558Srgrimes *endcp = savedc; 11311558Srgrimes } else { 11321558Srgrimes savedc = *endcp; 11331558Srgrimes *endcp = '\0'; 11341558Srgrimes got_nondir = 1; 11351558Srgrimes if (ep == (struct exportlist *)NULL) { 11361558Srgrimes getexp_err(ep, tgrp); 11371558Srgrimes goto nextline; 11381558Srgrimes } 11391558Srgrimes 11401558Srgrimes /* 11411558Srgrimes * Get the host or netgroup. 11421558Srgrimes */ 11431558Srgrimes setnetgrent(cp); 11441558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 11451558Srgrimes do { 11461558Srgrimes if (has_host) { 11471558Srgrimes grp->gr_next = get_grp(); 11481558Srgrimes grp = grp->gr_next; 11491558Srgrimes } 11501558Srgrimes if (netgrp) { 115137003Sjoerg if (hst == 0) { 115237663Scharnier syslog(LOG_ERR, 115337663Scharnier "null hostname in netgroup %s, skipping", cp); 115437004Sjoerg grp->gr_type = GT_IGNORE; 115537003Sjoerg } else if (get_host(hst, grp, tgrp)) { 115637663Scharnier syslog(LOG_ERR, 115737663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 115829317Sjlemon grp->gr_type = GT_IGNORE; 11591558Srgrimes } 11607401Swpaul } else if (get_host(cp, grp, tgrp)) { 116137663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 116229317Sjlemon grp->gr_type = GT_IGNORE; 11631558Srgrimes } 11641558Srgrimes has_host = TRUE; 11651558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 11661558Srgrimes endnetgrent(); 11671558Srgrimes *endcp = savedc; 11681558Srgrimes } 11691558Srgrimes cp = endcp; 11701558Srgrimes nextfield(&cp, &endcp); 11711558Srgrimes len = endcp - cp; 11721558Srgrimes } 11731558Srgrimes if (check_options(dirhead)) { 11741558Srgrimes getexp_err(ep, tgrp); 11751558Srgrimes goto nextline; 11761558Srgrimes } 11771558Srgrimes if (!has_host) { 117875641Siedowse grp->gr_type = GT_DEFAULT; 11791558Srgrimes if (debug) 118037663Scharnier warnx("adding a default entry"); 11811558Srgrimes 11821558Srgrimes /* 11831558Srgrimes * Don't allow a network export coincide with a list of 11841558Srgrimes * host(s) on the same line. 11851558Srgrimes */ 11861558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 118775801Siedowse syslog(LOG_ERR, "network/host conflict"); 11881558Srgrimes getexp_err(ep, tgrp); 11891558Srgrimes goto nextline; 119029317Sjlemon 119174462Salfred /* 119274462Salfred * If an export list was specified on this line, make sure 119329317Sjlemon * that we have at least one valid entry, otherwise skip it. 119429317Sjlemon */ 119529317Sjlemon } else { 119629317Sjlemon grp = tgrp; 119774462Salfred while (grp && grp->gr_type == GT_IGNORE) 119829317Sjlemon grp = grp->gr_next; 119929317Sjlemon if (! grp) { 120029317Sjlemon getexp_err(ep, tgrp); 120129317Sjlemon goto nextline; 120229317Sjlemon } 12031558Srgrimes } 12041558Srgrimes 12051558Srgrimes /* 12061558Srgrimes * Loop through hosts, pushing the exports into the kernel. 12071558Srgrimes * After loop, tgrp points to the start of the list and 12081558Srgrimes * grp points to the last entry in the list. 12091558Srgrimes */ 12101558Srgrimes grp = tgrp; 12111558Srgrimes do { 121275635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 121375635Siedowse &fsb)) { 121475635Siedowse getexp_err(ep, tgrp); 121575635Siedowse goto nextline; 121675635Siedowse } 12171558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 12181558Srgrimes 12191558Srgrimes /* 12201558Srgrimes * Success. Update the data structures. 12211558Srgrimes */ 12221558Srgrimes if (has_host) { 12239336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 12241558Srgrimes grp->gr_next = grphead; 12251558Srgrimes grphead = tgrp; 12261558Srgrimes } else { 12271558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 12289336Sdfr opt_flags); 12291558Srgrimes free_grp(grp); 12301558Srgrimes } 12311558Srgrimes dirhead = (struct dirlist *)NULL; 12321558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 12331558Srgrimes ep2 = exphead; 12341558Srgrimes epp = &exphead; 12351558Srgrimes 12361558Srgrimes /* 12371558Srgrimes * Insert in the list in alphabetical order. 12381558Srgrimes */ 12391558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 12401558Srgrimes epp = &ep2->ex_next; 12411558Srgrimes ep2 = ep2->ex_next; 12421558Srgrimes } 12431558Srgrimes if (ep2) 12441558Srgrimes ep->ex_next = ep2; 12451558Srgrimes *epp = ep; 12461558Srgrimes ep->ex_flag |= EX_LINKED; 12471558Srgrimes } 12481558Srgrimesnextline: 12491558Srgrimes if (dirhead) { 12501558Srgrimes free_dir(dirhead); 12511558Srgrimes dirhead = (struct dirlist *)NULL; 12521558Srgrimes } 12531558Srgrimes } 12541558Srgrimes fclose(exp_file); 12551558Srgrimes} 12561558Srgrimes 12571558Srgrimes/* 12581558Srgrimes * Allocate an export list element 12591558Srgrimes */ 12601558Srgrimesstruct exportlist * 12611558Srgrimesget_exp() 12621558Srgrimes{ 12631558Srgrimes struct exportlist *ep; 12641558Srgrimes 12651558Srgrimes ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 12661558Srgrimes if (ep == (struct exportlist *)NULL) 12671558Srgrimes out_of_mem(); 126823681Speter memset(ep, 0, sizeof(struct exportlist)); 12691558Srgrimes return (ep); 12701558Srgrimes} 12711558Srgrimes 12721558Srgrimes/* 12731558Srgrimes * Allocate a group list element 12741558Srgrimes */ 12751558Srgrimesstruct grouplist * 12761558Srgrimesget_grp() 12771558Srgrimes{ 12781558Srgrimes struct grouplist *gp; 12791558Srgrimes 12801558Srgrimes gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 12811558Srgrimes if (gp == (struct grouplist *)NULL) 12821558Srgrimes out_of_mem(); 128323681Speter memset(gp, 0, sizeof(struct grouplist)); 12841558Srgrimes return (gp); 12851558Srgrimes} 12861558Srgrimes 12871558Srgrimes/* 12881558Srgrimes * Clean up upon an error in get_exportlist(). 12891558Srgrimes */ 12901558Srgrimesvoid 12911558Srgrimesgetexp_err(ep, grp) 12921558Srgrimes struct exportlist *ep; 12931558Srgrimes struct grouplist *grp; 12941558Srgrimes{ 12951558Srgrimes struct grouplist *tgrp; 12961558Srgrimes 1297100336Sjoerg if (!(opt_flags & OP_QUIET)) 1298100336Sjoerg syslog(LOG_ERR, "bad exports list line %s", line); 12991558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 13001558Srgrimes free_exp(ep); 13011558Srgrimes while (grp) { 13021558Srgrimes tgrp = grp; 13031558Srgrimes grp = grp->gr_next; 13041558Srgrimes free_grp(tgrp); 13051558Srgrimes } 13061558Srgrimes} 13071558Srgrimes 13081558Srgrimes/* 13091558Srgrimes * Search the export list for a matching fs. 13101558Srgrimes */ 13111558Srgrimesstruct exportlist * 13121558Srgrimesex_search(fsid) 13131558Srgrimes fsid_t *fsid; 13141558Srgrimes{ 13151558Srgrimes struct exportlist *ep; 13161558Srgrimes 13171558Srgrimes ep = exphead; 13181558Srgrimes while (ep) { 13191558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 13201558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 13211558Srgrimes return (ep); 13221558Srgrimes ep = ep->ex_next; 13231558Srgrimes } 13241558Srgrimes return (ep); 13251558Srgrimes} 13261558Srgrimes 13271558Srgrimes/* 13281558Srgrimes * Add a directory path to the list. 13291558Srgrimes */ 13301558Srgrimeschar * 13311558Srgrimesadd_expdir(dpp, cp, len) 13321558Srgrimes struct dirlist **dpp; 13331558Srgrimes char *cp; 13341558Srgrimes int len; 13351558Srgrimes{ 13361558Srgrimes struct dirlist *dp; 13371558Srgrimes 13381558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 133937663Scharnier if (dp == (struct dirlist *)NULL) 134037663Scharnier out_of_mem(); 13411558Srgrimes dp->dp_left = *dpp; 13421558Srgrimes dp->dp_right = (struct dirlist *)NULL; 13431558Srgrimes dp->dp_flag = 0; 13441558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 13451558Srgrimes strcpy(dp->dp_dirp, cp); 13461558Srgrimes *dpp = dp; 13471558Srgrimes return (dp->dp_dirp); 13481558Srgrimes} 13491558Srgrimes 13501558Srgrimes/* 13511558Srgrimes * Hang the dir list element off the dirpath binary tree as required 13521558Srgrimes * and update the entry for host. 13531558Srgrimes */ 13541558Srgrimesvoid 13559336Sdfrhang_dirp(dp, grp, ep, flags) 13561558Srgrimes struct dirlist *dp; 13571558Srgrimes struct grouplist *grp; 13581558Srgrimes struct exportlist *ep; 13599336Sdfr int flags; 13601558Srgrimes{ 13611558Srgrimes struct hostlist *hp; 13621558Srgrimes struct dirlist *dp2; 13631558Srgrimes 13649336Sdfr if (flags & OP_ALLDIRS) { 13651558Srgrimes if (ep->ex_defdir) 13661558Srgrimes free((caddr_t)dp); 13671558Srgrimes else 13681558Srgrimes ep->ex_defdir = dp; 13699336Sdfr if (grp == (struct grouplist *)NULL) { 13701558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 13719336Sdfr } else while (grp) { 13721558Srgrimes hp = get_ht(); 13731558Srgrimes hp->ht_grp = grp; 13741558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 13751558Srgrimes ep->ex_defdir->dp_hosts = hp; 13761558Srgrimes grp = grp->gr_next; 13771558Srgrimes } 13781558Srgrimes } else { 13791558Srgrimes 13801558Srgrimes /* 138137663Scharnier * Loop through the directories adding them to the tree. 13821558Srgrimes */ 13831558Srgrimes while (dp) { 13841558Srgrimes dp2 = dp->dp_left; 13859336Sdfr add_dlist(&ep->ex_dirl, dp, grp, flags); 13861558Srgrimes dp = dp2; 13871558Srgrimes } 13881558Srgrimes } 13891558Srgrimes} 13901558Srgrimes 13911558Srgrimes/* 13921558Srgrimes * Traverse the binary tree either updating a node that is already there 13931558Srgrimes * for the new directory or adding the new node. 13941558Srgrimes */ 13951558Srgrimesvoid 13969336Sdfradd_dlist(dpp, newdp, grp, flags) 13971558Srgrimes struct dirlist **dpp; 13981558Srgrimes struct dirlist *newdp; 13991558Srgrimes struct grouplist *grp; 14009336Sdfr int flags; 14011558Srgrimes{ 14021558Srgrimes struct dirlist *dp; 14031558Srgrimes struct hostlist *hp; 14041558Srgrimes int cmp; 14051558Srgrimes 14061558Srgrimes dp = *dpp; 14071558Srgrimes if (dp) { 14081558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 14091558Srgrimes if (cmp > 0) { 14109336Sdfr add_dlist(&dp->dp_left, newdp, grp, flags); 14111558Srgrimes return; 14121558Srgrimes } else if (cmp < 0) { 14139336Sdfr add_dlist(&dp->dp_right, newdp, grp, flags); 14141558Srgrimes return; 14151558Srgrimes } else 14161558Srgrimes free((caddr_t)newdp); 14171558Srgrimes } else { 14181558Srgrimes dp = newdp; 14191558Srgrimes dp->dp_left = (struct dirlist *)NULL; 14201558Srgrimes *dpp = dp; 14211558Srgrimes } 14221558Srgrimes if (grp) { 14231558Srgrimes 14241558Srgrimes /* 14251558Srgrimes * Hang all of the host(s) off of the directory point. 14261558Srgrimes */ 14271558Srgrimes do { 14281558Srgrimes hp = get_ht(); 14291558Srgrimes hp->ht_grp = grp; 14301558Srgrimes hp->ht_next = dp->dp_hosts; 14311558Srgrimes dp->dp_hosts = hp; 14321558Srgrimes grp = grp->gr_next; 14331558Srgrimes } while (grp); 14349336Sdfr } else { 14351558Srgrimes dp->dp_flag |= DP_DEFSET; 14369336Sdfr } 14371558Srgrimes} 14381558Srgrimes 14391558Srgrimes/* 14401558Srgrimes * Search for a dirpath on the export point. 14411558Srgrimes */ 14421558Srgrimesstruct dirlist * 144374462Salfreddirp_search(dp, dirp) 14441558Srgrimes struct dirlist *dp; 144574462Salfred char *dirp; 14461558Srgrimes{ 14471558Srgrimes int cmp; 14481558Srgrimes 14491558Srgrimes if (dp) { 145074462Salfred cmp = strcmp(dp->dp_dirp, dirp); 14511558Srgrimes if (cmp > 0) 145274462Salfred return (dirp_search(dp->dp_left, dirp)); 14531558Srgrimes else if (cmp < 0) 145474462Salfred return (dirp_search(dp->dp_right, dirp)); 14551558Srgrimes else 14561558Srgrimes return (dp); 14571558Srgrimes } 14581558Srgrimes return (dp); 14591558Srgrimes} 14601558Srgrimes 14611558Srgrimes/* 14621558Srgrimes * Scan for a host match in a directory tree. 14631558Srgrimes */ 14641558Srgrimesint 14659336Sdfrchk_host(dp, saddr, defsetp, hostsetp) 14661558Srgrimes struct dirlist *dp; 146774462Salfred struct sockaddr *saddr; 14681558Srgrimes int *defsetp; 14699336Sdfr int *hostsetp; 14701558Srgrimes{ 14711558Srgrimes struct hostlist *hp; 14721558Srgrimes struct grouplist *grp; 147374462Salfred struct addrinfo *ai; 14741558Srgrimes 14751558Srgrimes if (dp) { 14761558Srgrimes if (dp->dp_flag & DP_DEFSET) 14779336Sdfr *defsetp = dp->dp_flag; 14781558Srgrimes hp = dp->dp_hosts; 14791558Srgrimes while (hp) { 14801558Srgrimes grp = hp->ht_grp; 14811558Srgrimes switch (grp->gr_type) { 14821558Srgrimes case GT_HOST: 148374462Salfred ai = grp->gr_ptr.gt_addrinfo; 148474462Salfred for (; ai; ai = ai->ai_next) { 148575801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 148674462Salfred *hostsetp = 148774462Salfred (hp->ht_flag | DP_HOSTSET); 148874462Salfred return (1); 148974462Salfred } 14909336Sdfr } 149175801Siedowse break; 14921558Srgrimes case GT_NET: 149375801Siedowse if (!sacmp(saddr, (struct sockaddr *) 149475801Siedowse &grp->gr_ptr.gt_net.nt_net, 149575801Siedowse (struct sockaddr *) 149675801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 149774462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 149874462Salfred return (1); 149974462Salfred } 150075801Siedowse break; 150175801Siedowse } 15021558Srgrimes hp = hp->ht_next; 15031558Srgrimes } 15041558Srgrimes } 15051558Srgrimes return (0); 15061558Srgrimes} 15071558Srgrimes 15081558Srgrimes/* 15091558Srgrimes * Scan tree for a host that matches the address. 15101558Srgrimes */ 15111558Srgrimesint 15121558Srgrimesscan_tree(dp, saddr) 15131558Srgrimes struct dirlist *dp; 151474462Salfred struct sockaddr *saddr; 15151558Srgrimes{ 15169336Sdfr int defset, hostset; 15171558Srgrimes 15181558Srgrimes if (dp) { 15191558Srgrimes if (scan_tree(dp->dp_left, saddr)) 15201558Srgrimes return (1); 15219336Sdfr if (chk_host(dp, saddr, &defset, &hostset)) 15221558Srgrimes return (1); 15231558Srgrimes if (scan_tree(dp->dp_right, saddr)) 15241558Srgrimes return (1); 15251558Srgrimes } 15261558Srgrimes return (0); 15271558Srgrimes} 15281558Srgrimes 15291558Srgrimes/* 15301558Srgrimes * Traverse the dirlist tree and free it up. 15311558Srgrimes */ 15321558Srgrimesvoid 15331558Srgrimesfree_dir(dp) 15341558Srgrimes struct dirlist *dp; 15351558Srgrimes{ 15361558Srgrimes 15371558Srgrimes if (dp) { 15381558Srgrimes free_dir(dp->dp_left); 15391558Srgrimes free_dir(dp->dp_right); 15401558Srgrimes free_host(dp->dp_hosts); 15411558Srgrimes free((caddr_t)dp); 15421558Srgrimes } 15431558Srgrimes} 15441558Srgrimes 15451558Srgrimes/* 15461558Srgrimes * Parse the option string and update fields. 15471558Srgrimes * Option arguments may either be -<option>=<value> or 15481558Srgrimes * -<option> <value> 15491558Srgrimes */ 15501558Srgrimesint 15511558Srgrimesdo_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 15521558Srgrimes char **cpp, **endcpp; 15531558Srgrimes struct exportlist *ep; 15541558Srgrimes struct grouplist *grp; 15551558Srgrimes int *has_hostp; 15561558Srgrimes int *exflagsp; 155772650Sgreen struct xucred *cr; 15581558Srgrimes{ 15591558Srgrimes char *cpoptarg, *cpoptend; 15601558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 15611558Srgrimes int allflag, usedarg; 15621558Srgrimes 156351968Salfred savedc2 = '\0'; 15641558Srgrimes cpopt = *cpp; 15651558Srgrimes cpopt++; 15661558Srgrimes cp = *endcpp; 15671558Srgrimes savedc = *cp; 15681558Srgrimes *cp = '\0'; 15691558Srgrimes while (cpopt && *cpopt) { 15701558Srgrimes allflag = 1; 15711558Srgrimes usedarg = -2; 157237663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 15731558Srgrimes *cpoptend++ = '\0'; 157437663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 15751558Srgrimes *cpoptarg++ = '\0'; 15761558Srgrimes } else { 157737663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 15781558Srgrimes *cpoptarg++ = '\0'; 15791558Srgrimes else { 15801558Srgrimes *cp = savedc; 15811558Srgrimes nextfield(&cp, &endcp); 15821558Srgrimes **endcpp = '\0'; 15831558Srgrimes if (endcp > cp && *cp != '-') { 15841558Srgrimes cpoptarg = cp; 15851558Srgrimes savedc2 = *endcp; 15861558Srgrimes *endcp = '\0'; 15871558Srgrimes usedarg = 0; 15881558Srgrimes } 15891558Srgrimes } 15901558Srgrimes } 15911558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 15921558Srgrimes *exflagsp |= MNT_EXRDONLY; 15931558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 15941558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 15951558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 15961558Srgrimes usedarg++; 15971558Srgrimes parsecred(cpoptarg, cr); 15981558Srgrimes if (allflag == 0) { 15991558Srgrimes *exflagsp |= MNT_EXPORTANON; 16001558Srgrimes opt_flags |= OP_MAPALL; 16011558Srgrimes } else 16021558Srgrimes opt_flags |= OP_MAPROOT; 16031558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 160475801Siedowse !strcmp(cpopt, "m"))) { 16051558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 160637663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 16071558Srgrimes return (1); 16081558Srgrimes } 16091558Srgrimes usedarg++; 16101558Srgrimes opt_flags |= OP_MASK; 16111558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 16121558Srgrimes !strcmp(cpopt, "n"))) { 161374462Salfred if (strchr(cpoptarg, '/') != NULL) { 161474462Salfred if (debug) 161574462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 161674462Salfred opt_flags |= OP_MASKLEN; 161774462Salfred } 16181558Srgrimes if (grp->gr_type != GT_NULL) { 161937663Scharnier syslog(LOG_ERR, "network/host conflict"); 16201558Srgrimes return (1); 16211558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 162237663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 16231558Srgrimes return (1); 16241558Srgrimes } 16251558Srgrimes grp->gr_type = GT_NET; 16261558Srgrimes *has_hostp = 1; 16271558Srgrimes usedarg++; 16281558Srgrimes opt_flags |= OP_NET; 16291558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 16301558Srgrimes opt_flags |= OP_ALLDIRS; 163127447Sdfr } else if (!strcmp(cpopt, "public")) { 163227447Sdfr *exflagsp |= MNT_EXPUBLIC; 163327447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 163427447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 163527447Sdfr opt_flags |= OP_MAPALL; 163627447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 163727447Sdfr ep->ex_indexfile = strdup(cpoptarg); 1638100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 1639100336Sjoerg opt_flags |= OP_QUIET; 16401558Srgrimes } else { 164137663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 16421558Srgrimes return (1); 16431558Srgrimes } 16441558Srgrimes if (usedarg >= 0) { 16451558Srgrimes *endcp = savedc2; 16461558Srgrimes **endcpp = savedc; 16471558Srgrimes if (usedarg > 0) { 16481558Srgrimes *cpp = cp; 16491558Srgrimes *endcpp = endcp; 16501558Srgrimes } 16511558Srgrimes return (0); 16521558Srgrimes } 16531558Srgrimes cpopt = cpoptend; 16541558Srgrimes } 16551558Srgrimes **endcpp = savedc; 16561558Srgrimes return (0); 16571558Srgrimes} 16581558Srgrimes 16591558Srgrimes/* 16601558Srgrimes * Translate a character string to the corresponding list of network 16611558Srgrimes * addresses for a hostname. 16621558Srgrimes */ 16631558Srgrimesint 16647401Swpaulget_host(cp, grp, tgrp) 16651558Srgrimes char *cp; 16661558Srgrimes struct grouplist *grp; 16677401Swpaul struct grouplist *tgrp; 16681558Srgrimes{ 16697401Swpaul struct grouplist *checkgrp; 167075635Siedowse struct addrinfo *ai, *tai, hints; 167174462Salfred int ecode; 167274462Salfred char host[NI_MAXHOST]; 16731558Srgrimes 167474462Salfred if (grp->gr_type != GT_NULL) { 167574462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 16761558Srgrimes return (1); 16771558Srgrimes } 167874462Salfred memset(&hints, 0, sizeof hints); 167974462Salfred hints.ai_flags = AI_CANONNAME; 168074462Salfred hints.ai_protocol = IPPROTO_UDP; 168174462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 168274462Salfred if (ecode != 0) { 168375635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 168474462Salfred return 1; 168574462Salfred } 168674462Salfred grp->gr_ptr.gt_addrinfo = ai; 168774462Salfred while (ai != NULL) { 168874462Salfred if (ai->ai_canonname == NULL) { 168974462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 1690146187Sume sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 169174462Salfred strlcpy(host, "?", sizeof(host)); 169274462Salfred ai->ai_canonname = strdup(host); 169374462Salfred ai->ai_flags |= AI_CANONNAME; 169475641Siedowse } 169574462Salfred if (debug) 169675635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 169775635Siedowse /* 169875635Siedowse * Sanity check: make sure we don't already have an entry 169975635Siedowse * for this host in the grouplist. 170075635Siedowse */ 170175635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 170275635Siedowse checkgrp = checkgrp->gr_next) { 170375635Siedowse if (checkgrp->gr_type != GT_HOST) 170475635Siedowse continue; 170575635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 170675635Siedowse tai = tai->ai_next) { 170775801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 170875635Siedowse continue; 170975635Siedowse if (debug) 171075635Siedowse fprintf(stderr, 171175635Siedowse "ignoring duplicate host %s\n", 171275635Siedowse ai->ai_canonname); 171375635Siedowse grp->gr_type = GT_IGNORE; 171475635Siedowse return (0); 171575635Siedowse } 171675635Siedowse } 171774462Salfred ai = ai->ai_next; 17181558Srgrimes } 171975635Siedowse grp->gr_type = GT_HOST; 17201558Srgrimes return (0); 17211558Srgrimes} 17221558Srgrimes 17231558Srgrimes/* 17241558Srgrimes * Free up an exports list component 17251558Srgrimes */ 17261558Srgrimesvoid 17271558Srgrimesfree_exp(ep) 17281558Srgrimes struct exportlist *ep; 17291558Srgrimes{ 17301558Srgrimes 17311558Srgrimes if (ep->ex_defdir) { 17321558Srgrimes free_host(ep->ex_defdir->dp_hosts); 17331558Srgrimes free((caddr_t)ep->ex_defdir); 17341558Srgrimes } 17351558Srgrimes if (ep->ex_fsdir) 17361558Srgrimes free(ep->ex_fsdir); 173727447Sdfr if (ep->ex_indexfile) 173827447Sdfr free(ep->ex_indexfile); 17391558Srgrimes free_dir(ep->ex_dirl); 17401558Srgrimes free((caddr_t)ep); 17411558Srgrimes} 17421558Srgrimes 17431558Srgrimes/* 17441558Srgrimes * Free hosts. 17451558Srgrimes */ 17461558Srgrimesvoid 17471558Srgrimesfree_host(hp) 17481558Srgrimes struct hostlist *hp; 17491558Srgrimes{ 17501558Srgrimes struct hostlist *hp2; 17511558Srgrimes 17521558Srgrimes while (hp) { 17531558Srgrimes hp2 = hp; 17541558Srgrimes hp = hp->ht_next; 17551558Srgrimes free((caddr_t)hp2); 17561558Srgrimes } 17571558Srgrimes} 17581558Srgrimes 17591558Srgrimesstruct hostlist * 17601558Srgrimesget_ht() 17611558Srgrimes{ 17621558Srgrimes struct hostlist *hp; 17631558Srgrimes 17641558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 17651558Srgrimes if (hp == (struct hostlist *)NULL) 17661558Srgrimes out_of_mem(); 17671558Srgrimes hp->ht_next = (struct hostlist *)NULL; 17689336Sdfr hp->ht_flag = 0; 17691558Srgrimes return (hp); 17701558Srgrimes} 17711558Srgrimes 17721558Srgrimes/* 17731558Srgrimes * Out of memory, fatal 17741558Srgrimes */ 17751558Srgrimesvoid 17761558Srgrimesout_of_mem() 17771558Srgrimes{ 17781558Srgrimes 177937663Scharnier syslog(LOG_ERR, "out of memory"); 17801558Srgrimes exit(2); 17811558Srgrimes} 17821558Srgrimes 17831558Srgrimes/* 17841558Srgrimes * Do the mount syscall with the update flag to push the export info into 17851558Srgrimes * the kernel. 17861558Srgrimes */ 17871558Srgrimesint 17881558Srgrimesdo_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 17891558Srgrimes struct exportlist *ep; 17901558Srgrimes struct grouplist *grp; 17911558Srgrimes int exflags; 179272650Sgreen struct xucred *anoncrp; 17931558Srgrimes char *dirp; 17941558Srgrimes int dirplen; 17951558Srgrimes struct statfs *fsb; 17961558Srgrimes{ 179775841Siedowse struct statfs fsb1; 179874462Salfred struct addrinfo *ai; 179975801Siedowse struct export_args *eap; 180074462Salfred char *cp = NULL; 18011558Srgrimes int done; 18021558Srgrimes char savedc = '\0'; 18031558Srgrimes union { 18041558Srgrimes struct ufs_args ua; 18051558Srgrimes struct iso_args ia; 18069336Sdfr struct msdosfs_args da; 180754093Ssemenu struct ntfs_args na; 18081558Srgrimes } args; 18091558Srgrimes 181075801Siedowse bzero(&args, sizeof args); 181175801Siedowse /* XXX, we assume that all xx_args look like ufs_args. */ 18121558Srgrimes args.ua.fspec = 0; 181375801Siedowse eap = &args.ua.export; 181475801Siedowse 181575801Siedowse eap->ex_flags = exflags; 181675801Siedowse eap->ex_anon = *anoncrp; 181775801Siedowse eap->ex_indexfile = ep->ex_indexfile; 181875641Siedowse if (grp->gr_type == GT_HOST) 181974462Salfred ai = grp->gr_ptr.gt_addrinfo; 182075641Siedowse else 182175641Siedowse ai = NULL; 18221558Srgrimes done = FALSE; 18231558Srgrimes while (!done) { 18241558Srgrimes switch (grp->gr_type) { 18251558Srgrimes case GT_HOST: 182675641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 182774462Salfred goto skip; 182875801Siedowse eap->ex_addr = ai->ai_addr; 182975801Siedowse eap->ex_addrlen = ai->ai_addrlen; 183075801Siedowse eap->ex_masklen = 0; 18311558Srgrimes break; 18321558Srgrimes case GT_NET: 183375801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 183474462Salfred have_v6 == 0) 183574462Salfred goto skip; 183675801Siedowse eap->ex_addr = 183775801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 183875801Siedowse eap->ex_addrlen = args.ua.export.ex_addr->sa_len; 183975801Siedowse eap->ex_mask = 184075801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 184175801Siedowse eap->ex_masklen = args.ua.export.ex_mask->sa_len; 18421558Srgrimes break; 184375641Siedowse case GT_DEFAULT: 184475801Siedowse eap->ex_addr = NULL; 184575801Siedowse eap->ex_addrlen = 0; 184675801Siedowse eap->ex_mask = NULL; 184775801Siedowse eap->ex_masklen = 0; 184875641Siedowse break; 18497401Swpaul case GT_IGNORE: 18507401Swpaul return(0); 18517401Swpaul break; 18521558Srgrimes default: 185337663Scharnier syslog(LOG_ERR, "bad grouptype"); 18541558Srgrimes if (cp) 18551558Srgrimes *cp = savedc; 18561558Srgrimes return (1); 18571558Srgrimes }; 18581558Srgrimes 18591558Srgrimes /* 18601558Srgrimes * XXX: 18611558Srgrimes * Maybe I should just use the fsb->f_mntonname path instead 18621558Srgrimes * of looping back up the dirp to the mount point?? 18631558Srgrimes * Also, needs to know how to export all types of local 186496707Strhodes * exportable filesystems and not just "ufs". 18651558Srgrimes */ 18669336Sdfr while (mount(fsb->f_fstypename, dirp, 186774462Salfred fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 18681558Srgrimes if (cp) 18691558Srgrimes *cp-- = savedc; 18701558Srgrimes else 18711558Srgrimes cp = dirp + dirplen - 1; 1872100336Sjoerg if (opt_flags & OP_QUIET) 1873100336Sjoerg return (1); 18741558Srgrimes if (errno == EPERM) { 187575635Siedowse if (debug) 187675635Siedowse warnx("can't change attributes for %s", 187775635Siedowse dirp); 18781558Srgrimes syslog(LOG_ERR, 187937663Scharnier "can't change attributes for %s", dirp); 18801558Srgrimes return (1); 18811558Srgrimes } 18821558Srgrimes if (opt_flags & OP_ALLDIRS) { 1883100336Sjoerg if (errno == EINVAL) 1884100336Sjoerg syslog(LOG_ERR, 1885100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 1886100336Sjoerg dirp); 1887100336Sjoerg else 1888100336Sjoerg syslog(LOG_ERR, 1889100336Sjoerg "could not remount %s: %m", 1890100336Sjoerg dirp); 18911558Srgrimes return (1); 18921558Srgrimes } 18931558Srgrimes /* back up over the last component */ 18941558Srgrimes while (*cp == '/' && cp > dirp) 18951558Srgrimes cp--; 18961558Srgrimes while (*(cp - 1) != '/' && cp > dirp) 18971558Srgrimes cp--; 18981558Srgrimes if (cp == dirp) { 18991558Srgrimes if (debug) 190037663Scharnier warnx("mnt unsucc"); 190137663Scharnier syslog(LOG_ERR, "can't export %s", dirp); 19021558Srgrimes return (1); 19031558Srgrimes } 19041558Srgrimes savedc = *cp; 19051558Srgrimes *cp = '\0'; 190675841Siedowse /* Check that we're still on the same filesystem. */ 190775841Siedowse if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid, 190875841Siedowse &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) { 190975841Siedowse *cp = savedc; 191075841Siedowse syslog(LOG_ERR, "can't export %s", dirp); 191175841Siedowse return (1); 191275841Siedowse } 19131558Srgrimes } 191474462Salfredskip: 191575641Siedowse if (ai != NULL) 191674462Salfred ai = ai->ai_next; 191775641Siedowse if (ai == NULL) 19181558Srgrimes done = TRUE; 19191558Srgrimes } 19201558Srgrimes if (cp) 19211558Srgrimes *cp = savedc; 19221558Srgrimes return (0); 19231558Srgrimes} 19241558Srgrimes 19251558Srgrimes/* 19261558Srgrimes * Translate a net address. 192775801Siedowse * 192875801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 19291558Srgrimes */ 19301558Srgrimesint 19311558Srgrimesget_net(cp, net, maskflg) 19321558Srgrimes char *cp; 19331558Srgrimes struct netmsk *net; 19341558Srgrimes int maskflg; 19351558Srgrimes{ 193675861Siedowse struct netent *np = NULL; 193774462Salfred char *name, *p, *prefp; 193875801Siedowse struct sockaddr_in sin; 193975861Siedowse struct sockaddr *sa = NULL; 194074462Salfred struct addrinfo hints, *ai = NULL; 194174462Salfred char netname[NI_MAXHOST]; 194274462Salfred long preflen; 19431558Srgrimes 194475635Siedowse p = prefp = NULL; 194574462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 194674462Salfred p = strchr(cp, '/'); 194774462Salfred *p = '\0'; 194874462Salfred prefp = p + 1; 194974462Salfred } 195074462Salfred 195175861Siedowse /* 195275861Siedowse * Check for a numeric address first. We wish to avoid 195375861Siedowse * possible DNS lookups in getnetbyname(). 195475861Siedowse */ 195575861Siedowse if (isxdigit(*cp) || *cp == ':') { 195674462Salfred memset(&hints, 0, sizeof hints); 195775801Siedowse /* Ensure the mask and the network have the same family. */ 195875801Siedowse if (maskflg && (opt_flags & OP_NET)) 195975801Siedowse hints.ai_family = net->nt_net.ss_family; 196075801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 196175801Siedowse hints.ai_family = net->nt_mask.ss_family; 196275801Siedowse else 196375801Siedowse hints.ai_family = AF_UNSPEC; 196474462Salfred hints.ai_flags = AI_NUMERICHOST; 196575861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 196675861Siedowse sa = ai->ai_addr; 196775861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 196874462Salfred /* 196975801Siedowse * The address in `cp' is really a network address, so 197075801Siedowse * use inet_network() to re-interpret this correctly. 197175801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 197274462Salfred */ 197375801Siedowse bzero(&sin, sizeof sin); 197474462Salfred sin.sin_family = AF_INET; 197574462Salfred sin.sin_len = sizeof sin; 197675801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 197774462Salfred if (debug) 197875801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 197975801Siedowse inet_ntoa(sin.sin_addr)); 198074462Salfred sa = (struct sockaddr *)&sin; 198175861Siedowse } 198275861Siedowse } 198375861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 198475861Siedowse bzero(&sin, sizeof sin); 198575861Siedowse sin.sin_family = AF_INET; 198675861Siedowse sin.sin_len = sizeof sin; 198775861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 198875861Siedowse sa = (struct sockaddr *)&sin; 198975861Siedowse } 199075861Siedowse if (sa == NULL) 199174462Salfred goto fail; 199225318Spst 199375801Siedowse if (maskflg) { 199475801Siedowse /* The specified sockaddr is a mask. */ 199575801Siedowse if (checkmask(sa) != 0) 199675801Siedowse goto fail; 199775801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 199875801Siedowse opt_flags |= OP_HAVEMASK; 199975801Siedowse } else { 200075801Siedowse /* The specified sockaddr is a network address. */ 200175801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 200274462Salfred 200375801Siedowse /* Get a network name for the export list. */ 200475801Siedowse if (np) { 200575801Siedowse name = np->n_name; 200675801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2007146187Sume NULL, 0, NI_NUMERICHOST) == 0) { 200875801Siedowse name = netname; 200975801Siedowse } else { 201075801Siedowse goto fail; 201175801Siedowse } 201275801Siedowse if ((net->nt_name = strdup(name)) == NULL) 201375801Siedowse out_of_mem(); 201475801Siedowse 201575801Siedowse /* 201675801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 201775801Siedowse * from the class of an IPv4 address. 201875801Siedowse */ 201974462Salfred if (opt_flags & OP_MASKLEN) { 202074462Salfred preflen = strtol(prefp, NULL, 10); 202175801Siedowse if (preflen < 0L || preflen == LONG_MAX) 202274462Salfred goto fail; 202375801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 202475801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 202575801Siedowse goto fail; 202675801Siedowse opt_flags |= OP_HAVEMASK; 202774462Salfred *p = '/'; 202875801Siedowse } else if (sa->sa_family == AF_INET && 202975801Siedowse (opt_flags & OP_MASK) == 0) { 203075801Siedowse in_addr_t addr; 203174462Salfred 203275801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 203375801Siedowse if (IN_CLASSA(addr)) 203475801Siedowse preflen = 8; 203575801Siedowse else if (IN_CLASSB(addr)) 203675801Siedowse preflen = 16; 203775801Siedowse else if (IN_CLASSC(addr)) 203875801Siedowse preflen = 24; 203975801Siedowse else if (IN_CLASSD(addr)) 204075801Siedowse preflen = 28; 204175801Siedowse else 204275801Siedowse preflen = 32; /* XXX */ 204375801Siedowse 204475801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 204575801Siedowse makemask(&net->nt_mask, (int)preflen); 204675801Siedowse opt_flags |= OP_HAVEMASK; 204774462Salfred } 204874462Salfred } 204974462Salfred 205074462Salfred if (ai) 205174462Salfred freeaddrinfo(ai); 205274462Salfred return 0; 205374462Salfred 205474462Salfredfail: 205574462Salfred if (ai) 205674462Salfred freeaddrinfo(ai); 205774462Salfred return 1; 20581558Srgrimes} 20591558Srgrimes 20601558Srgrimes/* 20611558Srgrimes * Parse out the next white space separated field 20621558Srgrimes */ 20631558Srgrimesvoid 20641558Srgrimesnextfield(cp, endcp) 20651558Srgrimes char **cp; 20661558Srgrimes char **endcp; 20671558Srgrimes{ 20681558Srgrimes char *p; 20691558Srgrimes 20701558Srgrimes p = *cp; 20711558Srgrimes while (*p == ' ' || *p == '\t') 20721558Srgrimes p++; 20731558Srgrimes if (*p == '\n' || *p == '\0') 20741558Srgrimes *cp = *endcp = p; 20751558Srgrimes else { 20761558Srgrimes *cp = p++; 20771558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 20781558Srgrimes p++; 20791558Srgrimes *endcp = p; 20801558Srgrimes } 20811558Srgrimes} 20821558Srgrimes 20831558Srgrimes/* 20841558Srgrimes * Get an exports file line. Skip over blank lines and handle line 20851558Srgrimes * continuations. 20861558Srgrimes */ 20871558Srgrimesint 20881558Srgrimesget_line() 20891558Srgrimes{ 20901558Srgrimes char *p, *cp; 209196622Siedowse size_t len; 20921558Srgrimes int totlen, cont_line; 20931558Srgrimes 20941558Srgrimes /* 20951558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 20961558Srgrimes */ 20971558Srgrimes p = line; 20981558Srgrimes totlen = 0; 20991558Srgrimes do { 210096622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 21011558Srgrimes return (0); 21021558Srgrimes cp = p + len - 1; 21031558Srgrimes cont_line = 0; 21041558Srgrimes while (cp >= p && 21051558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 21061558Srgrimes if (*cp == '\\') 21071558Srgrimes cont_line = 1; 21081558Srgrimes cp--; 21091558Srgrimes len--; 21101558Srgrimes } 211179117Sdd if (cont_line) { 211279117Sdd *++cp = ' '; 211379117Sdd len++; 211479117Sdd } 211596622Siedowse if (linesize < len + totlen + 1) { 211696622Siedowse linesize = len + totlen + 1; 211796622Siedowse line = realloc(line, linesize); 211896622Siedowse if (line == NULL) 211996622Siedowse out_of_mem(); 21201558Srgrimes } 212196622Siedowse memcpy(line + totlen, p, len); 212296622Siedowse totlen += len; 212396622Siedowse line[totlen] = '\0'; 21241558Srgrimes } while (totlen == 0 || cont_line); 21251558Srgrimes return (1); 21261558Srgrimes} 21271558Srgrimes 21281558Srgrimes/* 21291558Srgrimes * Parse a description of a credential. 21301558Srgrimes */ 21311558Srgrimesvoid 21321558Srgrimesparsecred(namelist, cr) 21331558Srgrimes char *namelist; 213472650Sgreen struct xucred *cr; 21351558Srgrimes{ 21361558Srgrimes char *name; 21371558Srgrimes int cnt; 21381558Srgrimes char *names; 21391558Srgrimes struct passwd *pw; 21401558Srgrimes struct group *gr; 2141136051Sstefanf gid_t groups[NGROUPS + 1]; 2142136051Sstefanf int ngroups; 21431558Srgrimes 214491354Sdd cr->cr_version = XUCRED_VERSION; 21451558Srgrimes /* 214637663Scharnier * Set up the unprivileged user. 21471558Srgrimes */ 21481558Srgrimes cr->cr_uid = -2; 21491558Srgrimes cr->cr_groups[0] = -2; 21501558Srgrimes cr->cr_ngroups = 1; 21511558Srgrimes /* 21521558Srgrimes * Get the user's password table entry. 21531558Srgrimes */ 21541558Srgrimes names = strsep(&namelist, " \t\n"); 21551558Srgrimes name = strsep(&names, ":"); 21561558Srgrimes if (isdigit(*name) || *name == '-') 21571558Srgrimes pw = getpwuid(atoi(name)); 21581558Srgrimes else 21591558Srgrimes pw = getpwnam(name); 21601558Srgrimes /* 21611558Srgrimes * Credentials specified as those of a user. 21621558Srgrimes */ 21631558Srgrimes if (names == NULL) { 21641558Srgrimes if (pw == NULL) { 216537663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 21661558Srgrimes return; 21671558Srgrimes } 21681558Srgrimes cr->cr_uid = pw->pw_uid; 21691558Srgrimes ngroups = NGROUPS + 1; 21701558Srgrimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 217137663Scharnier syslog(LOG_ERR, "too many groups"); 21721558Srgrimes /* 2173136051Sstefanf * Compress out duplicate. 21741558Srgrimes */ 21751558Srgrimes cr->cr_ngroups = ngroups - 1; 21761558Srgrimes cr->cr_groups[0] = groups[0]; 21771558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 21781558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 21791558Srgrimes return; 21801558Srgrimes } 21811558Srgrimes /* 21821558Srgrimes * Explicit credential specified as a colon separated list: 21831558Srgrimes * uid:gid:gid:... 21841558Srgrimes */ 21851558Srgrimes if (pw != NULL) 21861558Srgrimes cr->cr_uid = pw->pw_uid; 21871558Srgrimes else if (isdigit(*name) || *name == '-') 21881558Srgrimes cr->cr_uid = atoi(name); 21891558Srgrimes else { 219037663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 21911558Srgrimes return; 21921558Srgrimes } 21931558Srgrimes cr->cr_ngroups = 0; 21941558Srgrimes while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 21951558Srgrimes name = strsep(&names, ":"); 21961558Srgrimes if (isdigit(*name) || *name == '-') { 21971558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 21981558Srgrimes } else { 21991558Srgrimes if ((gr = getgrnam(name)) == NULL) { 220037663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 22011558Srgrimes continue; 22021558Srgrimes } 22031558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 22041558Srgrimes } 22051558Srgrimes } 22061558Srgrimes if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 220737663Scharnier syslog(LOG_ERR, "too many groups"); 22081558Srgrimes} 22091558Srgrimes 22101558Srgrimes#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 22111558Srgrimes/* 22121558Srgrimes * Routines that maintain the remote mounttab 22131558Srgrimes */ 22141558Srgrimesvoid 22151558Srgrimesget_mountlist() 22161558Srgrimes{ 22171558Srgrimes struct mountlist *mlp, **mlpp; 221823681Speter char *host, *dirp, *cp; 22191558Srgrimes char str[STRSIZ]; 22201558Srgrimes FILE *mlfile; 22211558Srgrimes 22221558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 222353117Sbillf if (errno == ENOENT) 222453117Sbillf return; 222553117Sbillf else { 222653117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 222753117Sbillf return; 222853117Sbillf } 22291558Srgrimes } 22301558Srgrimes mlpp = &mlhead; 22311558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 223223681Speter cp = str; 223323681Speter host = strsep(&cp, " \t\n"); 223423681Speter dirp = strsep(&cp, " \t\n"); 223523681Speter if (host == NULL || dirp == NULL) 22361558Srgrimes continue; 22371558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 223837663Scharnier if (mlp == (struct mountlist *)NULL) 223937663Scharnier out_of_mem(); 224023681Speter strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 224123681Speter mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 224223681Speter strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 224323681Speter mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 22441558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 22451558Srgrimes *mlpp = mlp; 22461558Srgrimes mlpp = &mlp->ml_next; 22471558Srgrimes } 22481558Srgrimes fclose(mlfile); 22491558Srgrimes} 22501558Srgrimes 225175635Siedowsevoid 225275635Siedowsedel_mlist(char *hostp, char *dirp) 22531558Srgrimes{ 22541558Srgrimes struct mountlist *mlp, **mlpp; 22551558Srgrimes struct mountlist *mlp2; 22561558Srgrimes FILE *mlfile; 22571558Srgrimes int fnd = 0; 22581558Srgrimes 22591558Srgrimes mlpp = &mlhead; 22601558Srgrimes mlp = mlhead; 22611558Srgrimes while (mlp) { 22621558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 22631558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 22641558Srgrimes fnd = 1; 22651558Srgrimes mlp2 = mlp; 22661558Srgrimes *mlpp = mlp = mlp->ml_next; 22671558Srgrimes free((caddr_t)mlp2); 22681558Srgrimes } else { 22691558Srgrimes mlpp = &mlp->ml_next; 22701558Srgrimes mlp = mlp->ml_next; 22711558Srgrimes } 22721558Srgrimes } 22731558Srgrimes if (fnd) { 22741558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 227537663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 22761558Srgrimes return; 22771558Srgrimes } 22781558Srgrimes mlp = mlhead; 22791558Srgrimes while (mlp) { 22801558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 22811558Srgrimes mlp = mlp->ml_next; 22821558Srgrimes } 22831558Srgrimes fclose(mlfile); 22841558Srgrimes } 22851558Srgrimes} 22861558Srgrimes 22871558Srgrimesvoid 22881558Srgrimesadd_mlist(hostp, dirp) 22891558Srgrimes char *hostp, *dirp; 22901558Srgrimes{ 22911558Srgrimes struct mountlist *mlp, **mlpp; 22921558Srgrimes FILE *mlfile; 22931558Srgrimes 22941558Srgrimes mlpp = &mlhead; 22951558Srgrimes mlp = mlhead; 22961558Srgrimes while (mlp) { 22971558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 22981558Srgrimes return; 22991558Srgrimes mlpp = &mlp->ml_next; 23001558Srgrimes mlp = mlp->ml_next; 23011558Srgrimes } 23021558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 230337663Scharnier if (mlp == (struct mountlist *)NULL) 230437663Scharnier out_of_mem(); 23051558Srgrimes strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 23061558Srgrimes mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 23071558Srgrimes strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 23081558Srgrimes mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 23091558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 23101558Srgrimes *mlpp = mlp; 23111558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 231237663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 23131558Srgrimes return; 23141558Srgrimes } 23151558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 23161558Srgrimes fclose(mlfile); 23171558Srgrimes} 23181558Srgrimes 23191558Srgrimes/* 23201558Srgrimes * Free up a group list. 23211558Srgrimes */ 23221558Srgrimesvoid 23231558Srgrimesfree_grp(grp) 23241558Srgrimes struct grouplist *grp; 23251558Srgrimes{ 23261558Srgrimes if (grp->gr_type == GT_HOST) { 232774462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 232874462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 23291558Srgrimes } else if (grp->gr_type == GT_NET) { 23301558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 23311558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 23321558Srgrimes } 23331558Srgrimes free((caddr_t)grp); 23341558Srgrimes} 23351558Srgrimes 23361558Srgrimes#ifdef DEBUG 23371558Srgrimesvoid 23381558SrgrimesSYSLOG(int pri, const char *fmt, ...) 23391558Srgrimes{ 23401558Srgrimes va_list ap; 23411558Srgrimes 23421558Srgrimes va_start(ap, fmt); 23431558Srgrimes vfprintf(stderr, fmt, ap); 23441558Srgrimes va_end(ap); 23451558Srgrimes} 23461558Srgrimes#endif /* DEBUG */ 23471558Srgrimes 23481558Srgrimes/* 23491558Srgrimes * Check options for consistency. 23501558Srgrimes */ 23511558Srgrimesint 23521558Srgrimescheck_options(dp) 23531558Srgrimes struct dirlist *dp; 23541558Srgrimes{ 23551558Srgrimes 23561558Srgrimes if (dp == (struct dirlist *)NULL) 23571558Srgrimes return (1); 235883653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 235983653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 23601558Srgrimes return (1); 23611558Srgrimes } 23621558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 236375801Siedowse syslog(LOG_ERR, "-mask requires -network"); 236475801Siedowse return (1); 23651558Srgrimes } 236675801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 236775801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 236875801Siedowse return (1); 236975801Siedowse } 237075801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 237175801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 237275801Siedowse return (1); 237375801Siedowse } 23741558Srgrimes if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 237545927Salex syslog(LOG_ERR, "-alldirs has multiple directories"); 23761558Srgrimes return (1); 23771558Srgrimes } 23781558Srgrimes return (0); 23791558Srgrimes} 23801558Srgrimes 23811558Srgrimes/* 23821558Srgrimes * Check an absolute directory path for any symbolic links. Return true 23831558Srgrimes */ 23841558Srgrimesint 23851558Srgrimescheck_dirpath(dirp) 23861558Srgrimes char *dirp; 23871558Srgrimes{ 23881558Srgrimes char *cp; 23891558Srgrimes int ret = 1; 23901558Srgrimes struct stat sb; 23911558Srgrimes 23921558Srgrimes cp = dirp + 1; 23931558Srgrimes while (*cp && ret) { 23941558Srgrimes if (*cp == '/') { 23951558Srgrimes *cp = '\0'; 23969336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 23971558Srgrimes ret = 0; 23981558Srgrimes *cp = '/'; 23991558Srgrimes } 24001558Srgrimes cp++; 24011558Srgrimes } 24029336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 24031558Srgrimes ret = 0; 24041558Srgrimes return (ret); 24051558Srgrimes} 24069336Sdfr 240775801Siedowse/* 240875801Siedowse * Make a netmask according to the specified prefix length. The ss_family 240975801Siedowse * and other non-address fields must be initialised before calling this. 241075801Siedowse */ 241175801Siedowseint 241275801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 241374462Salfred{ 241475801Siedowse u_char *p; 241575801Siedowse int bits, i, len; 241674462Salfred 241775801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 241875801Siedowse return (-1); 2419103949Smike if (bitlen > len * CHAR_BIT) 242075801Siedowse return (-1); 242174462Salfred 242275801Siedowse for (i = 0; i < len; i++) { 2423103949Smike bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 242475801Siedowse *p++ = (1 << bits) - 1; 242575801Siedowse bitlen -= bits; 242674462Salfred } 242775801Siedowse return 0; 242874462Salfred} 242974462Salfred 243075801Siedowse/* 243175801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 243275801Siedowse * is acceptable (i.e. of the form 1...10....0). 243375801Siedowse */ 243475801Siedowseint 243575801Siedowsecheckmask(struct sockaddr *sa) 243674462Salfred{ 243775801Siedowse u_char *mask; 243875801Siedowse int i, len; 243974462Salfred 244075801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 244175801Siedowse return (-1); 244275801Siedowse 244375801Siedowse for (i = 0; i < len; i++) 244475801Siedowse if (mask[i] != 0xff) 244575801Siedowse break; 244675801Siedowse if (i < len) { 244775801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 244875801Siedowse return (-1); 244975801Siedowse i++; 245074462Salfred } 245175801Siedowse for (; i < len; i++) 245275801Siedowse if (mask[i] != 0) 245375801Siedowse return (-1); 245475801Siedowse return (0); 245574462Salfred} 245674462Salfred 245775801Siedowse/* 245875801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 245975801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 246075801Siedowse * If samask is NULL, perform a full comparision. 246175801Siedowse */ 246275801Siedowseint 246375801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 246474462Salfred{ 246575801Siedowse unsigned char *p1, *p2, *mask; 246675801Siedowse int len, i; 246774462Salfred 246875801Siedowse if (sa1->sa_family != sa2->sa_family || 246975801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 247075801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 247175801Siedowse return (1); 247275801Siedowse 247375801Siedowse switch (sa1->sa_family) { 247474462Salfred case AF_INET6: 247575801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 247675801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 247775801Siedowse return (1); 247874462Salfred break; 247974462Salfred } 248074462Salfred 248175801Siedowse /* Simple binary comparison if no mask specified. */ 248275801Siedowse if (samask == NULL) 248375801Siedowse return (memcmp(p1, p2, len)); 248474462Salfred 248575801Siedowse /* Set up the mask, and do a mask-based comparison. */ 248675801Siedowse if (sa1->sa_family != samask->sa_family || 248775801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 248875801Siedowse return (1); 248974462Salfred 249075801Siedowse for (i = 0; i < len; i++) 249175801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 249275801Siedowse return (1); 249375801Siedowse return (0); 249474462Salfred} 249574462Salfred 249675801Siedowse/* 249775801Siedowse * Return a pointer to the part of the sockaddr that contains the 249875801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 249975801Siedowse * NULL if the address family is unknown. 250075801Siedowse */ 250175801Siedowsevoid * 250275801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 250375801Siedowse void *p; 250474462Salfred int len; 250574462Salfred 250675801Siedowse switch (sa->sa_family) { 250774462Salfred case AF_INET: 250875801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 250975801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 251074462Salfred break; 251174462Salfred case AF_INET6: 251275801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 251375801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 251474462Salfred break; 251574462Salfred default: 251675801Siedowse p = NULL; 251775801Siedowse len = 0; 251874462Salfred } 251974462Salfred 252075801Siedowse if (nbytes != NULL) 252175801Siedowse *nbytes = len; 252275801Siedowse return (p); 252374462Salfred} 252474462Salfred 252575754Siedowsevoid 252675754Siedowsehuphandler(int sig) 252775754Siedowse{ 252875754Siedowse got_sighup = 1; 252975754Siedowse} 253075754Siedowse 253174462Salfredvoid terminate(sig) 253274462Salfredint sig; 253374462Salfred{ 253474462Salfred close(mountdlockfd); 253574462Salfred unlink(MOUNTDLOCK); 253674792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 253774792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 253874462Salfred exit (0); 253974462Salfred} 2540