mountd.c revision 149433
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 149433 2005-08-24 19:17:06Z pjd $"); 47105267Scharnier 481558Srgrimes#include <sys/param.h> 491558Srgrimes#include <sys/mount.h> 5074462Salfred#include <sys/fcntl.h> 511558Srgrimes#include <sys/stat.h> 521558Srgrimes#include <sys/syslog.h> 5324330Sguido#include <sys/sysctl.h> 5496622Siedowse#include <sys/linker.h> 5596622Siedowse#include <sys/module.h> 561558Srgrimes 571558Srgrimes#include <rpc/rpc.h> 58109363Smbr#include <rpc/rpc_com.h> 591558Srgrimes#include <rpc/pmap_clnt.h> 6074462Salfred#include <rpc/pmap_prot.h> 6174462Salfred#include <rpcsvc/mount.h> 621558Srgrimes#include <nfs/rpcv2.h> 639336Sdfr#include <nfs/nfsproto.h> 6483653Speter#include <nfsserver/nfs.h> 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> 76149433Spjd#include <libutil.h> 77103949Smike#include <limits.h> 781558Srgrimes#include <netdb.h> 791558Srgrimes#include <pwd.h> 801558Srgrimes#include <signal.h> 811558Srgrimes#include <stdio.h> 821558Srgrimes#include <stdlib.h> 831558Srgrimes#include <string.h> 841558Srgrimes#include <unistd.h> 851558Srgrimes#include "pathnames.h" 861558Srgrimes 871558Srgrimes#ifdef DEBUG 881558Srgrimes#include <stdarg.h> 891558Srgrimes#endif 901558Srgrimes 911558Srgrimes/* 921558Srgrimes * Structures for keeping the mount list and export list 931558Srgrimes */ 941558Srgrimesstruct mountlist { 951558Srgrimes struct mountlist *ml_next; 961558Srgrimes char ml_host[RPCMNT_NAMELEN+1]; 971558Srgrimes char ml_dirp[RPCMNT_PATHLEN+1]; 981558Srgrimes}; 991558Srgrimes 1001558Srgrimesstruct dirlist { 1011558Srgrimes struct dirlist *dp_left; 1021558Srgrimes struct dirlist *dp_right; 1031558Srgrimes int dp_flag; 1041558Srgrimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 1051558Srgrimes char dp_dirp[1]; /* Actually malloc'd to size of dir */ 1061558Srgrimes}; 1071558Srgrimes/* dp_flag bits */ 1081558Srgrimes#define DP_DEFSET 0x1 1099336Sdfr#define DP_HOSTSET 0x2 1101558Srgrimes 1111558Srgrimesstruct exportlist { 1121558Srgrimes struct exportlist *ex_next; 1131558Srgrimes struct dirlist *ex_dirl; 1141558Srgrimes struct dirlist *ex_defdir; 1151558Srgrimes int ex_flag; 1161558Srgrimes fsid_t ex_fs; 1171558Srgrimes char *ex_fsdir; 11827447Sdfr char *ex_indexfile; 1191558Srgrimes}; 1201558Srgrimes/* ex_flag bits */ 1211558Srgrimes#define EX_LINKED 0x1 1221558Srgrimes 1231558Srgrimesstruct netmsk { 12474462Salfred struct sockaddr_storage nt_net; 12575801Siedowse struct sockaddr_storage nt_mask; 12642144Sdfr char *nt_name; 1271558Srgrimes}; 1281558Srgrimes 1291558Srgrimesunion grouptypes { 13074462Salfred struct addrinfo *gt_addrinfo; 1311558Srgrimes struct netmsk gt_net; 1321558Srgrimes}; 1331558Srgrimes 1341558Srgrimesstruct grouplist { 1351558Srgrimes int gr_type; 1361558Srgrimes union grouptypes gr_ptr; 1371558Srgrimes struct grouplist *gr_next; 1381558Srgrimes}; 1391558Srgrimes/* Group types */ 1401558Srgrimes#define GT_NULL 0x0 1411558Srgrimes#define GT_HOST 0x1 1421558Srgrimes#define GT_NET 0x2 14375641Siedowse#define GT_DEFAULT 0x3 1447401Swpaul#define GT_IGNORE 0x5 1451558Srgrimes 1461558Srgrimesstruct hostlist { 1479336Sdfr int ht_flag; /* Uses DP_xx bits */ 1481558Srgrimes struct grouplist *ht_grp; 1491558Srgrimes struct hostlist *ht_next; 1501558Srgrimes}; 1511558Srgrimes 1529336Sdfrstruct fhreturn { 1539336Sdfr int fhr_flag; 1549336Sdfr int fhr_vers; 1559336Sdfr nfsfh_t fhr_fh; 1569336Sdfr}; 1579336Sdfr 1581558Srgrimes/* Global defs */ 15992882Simpchar *add_expdir(struct dirlist **, char *, int); 16092882Simpvoid add_dlist(struct dirlist **, struct dirlist *, 16192882Simp struct grouplist *, int); 16292882Simpvoid add_mlist(char *, char *); 16392882Simpint check_dirpath(char *); 16492882Simpint check_options(struct dirlist *); 16575801Siedowseint checkmask(struct sockaddr *sa); 16692882Simpint chk_host(struct dirlist *, struct sockaddr *, int *, int *); 16775635Siedowsevoid del_mlist(char *hostp, char *dirp); 16892882Simpstruct dirlist *dirp_search(struct dirlist *, char *); 16992882Simpint do_mount(struct exportlist *, struct grouplist *, int, 17092882Simp struct xucred *, char *, int, struct statfs *); 17192882Simpint do_opt(char **, char **, struct exportlist *, struct grouplist *, 17292882Simp int *, int *, struct xucred *); 17392882Simpstruct exportlist *ex_search(fsid_t *); 17492882Simpstruct exportlist *get_exp(void); 17592882Simpvoid free_dir(struct dirlist *); 17692882Simpvoid free_exp(struct exportlist *); 17792882Simpvoid free_grp(struct grouplist *); 17892882Simpvoid free_host(struct hostlist *); 17992882Simpvoid get_exportlist(void); 18092882Simpint get_host(char *, struct grouplist *, struct grouplist *); 18192882Simpstruct hostlist *get_ht(void); 18292882Simpint get_line(void); 18392882Simpvoid get_mountlist(void); 18492882Simpint get_net(char *, struct netmsk *, int); 18592882Simpvoid getexp_err(struct exportlist *, struct grouplist *); 18692882Simpstruct grouplist *get_grp(void); 18792882Simpvoid hang_dirp(struct dirlist *, struct grouplist *, 18892882Simp struct exportlist *, int); 18975754Siedowsevoid huphandler(int sig); 19075801Siedowseint makemask(struct sockaddr_storage *ssp, int bitlen); 19192882Simpvoid mntsrv(struct svc_req *, SVCXPRT *); 19292882Simpvoid nextfield(char **, char **); 19392882Simpvoid out_of_mem(void); 19492882Simpvoid parsecred(char *, struct xucred *); 195100117Salfredint put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 19675801Siedowsevoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 19775801Siedowseint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 19875801Siedowse struct sockaddr *samask); 19992882Simpint scan_tree(struct dirlist *, struct sockaddr *); 20092882Simpstatic void usage(void); 20192882Simpint xdr_dir(XDR *, char *); 20292882Simpint xdr_explist(XDR *, caddr_t); 203100117Salfredint xdr_explist_brief(XDR *, caddr_t); 20492882Simpint xdr_fhs(XDR *, caddr_t); 20592882Simpint xdr_mlist(XDR *, caddr_t); 20692882Simpvoid terminate(int); 2071558Srgrimes 2081558Srgrimesstruct exportlist *exphead; 2091558Srgrimesstruct mountlist *mlhead; 2101558Srgrimesstruct grouplist *grphead; 2111558Srgrimeschar exname[MAXPATHLEN]; 21272650Sgreenstruct xucred def_anon = { 21391354Sdd XUCRED_VERSION, 21472650Sgreen (uid_t)-2, 2151558Srgrimes 1, 21672650Sgreen { (gid_t)-2 }, 21772650Sgreen NULL 2181558Srgrimes}; 21925087Sdfrint force_v2 = 0; 2209336Sdfrint resvport_only = 1; 2219336Sdfrint dir_only = 1; 222121767Speterint dolog = 0; 22375754Siedowseint got_sighup = 0; 22474462Salfred 2251558Srgrimesint opt_flags; 22674462Salfredstatic int have_v6 = 1; 22774462Salfred 228149433Spjdstruct pidfh *pfh = NULL; 22975801Siedowse/* Bits for opt_flags above */ 2301558Srgrimes#define OP_MAPROOT 0x01 2311558Srgrimes#define OP_MAPALL 0x02 23283653Speter/* 0x4 free */ 2331558Srgrimes#define OP_MASK 0x08 2341558Srgrimes#define OP_NET 0x10 2351558Srgrimes#define OP_ALLDIRS 0x40 23675801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 237100336Sjoerg#define OP_QUIET 0x100 23874462Salfred#define OP_MASKLEN 0x200 2391558Srgrimes 2401558Srgrimes#ifdef DEBUG 2411558Srgrimesint debug = 1; 24292882Simpvoid SYSLOG(int, const char *, ...) __printflike(2, 3); 2431558Srgrimes#define syslog SYSLOG 2441558Srgrimes#else 2451558Srgrimesint debug = 0; 2461558Srgrimes#endif 2471558Srgrimes 2481558Srgrimes/* 2491558Srgrimes * Mountd server for NFS mount protocol as described in: 2501558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 2511558Srgrimes * The optional arguments are the exports file name 2521558Srgrimes * default: _PATH_EXPORTS 2531558Srgrimes * and "-n" to allow nonroot mount. 2541558Srgrimes */ 2551558Srgrimesint 2561558Srgrimesmain(argc, argv) 2571558Srgrimes int argc; 2581558Srgrimes char **argv; 2591558Srgrimes{ 26075754Siedowse fd_set readfds; 261126572Sbms struct sockaddr_in sin; 262126572Sbms struct sockaddr_in6 sin6; 263126572Sbms char *endptr; 26474462Salfred SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; 26574462Salfred struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 266149433Spjd pid_t otherpid; 26774462Salfred int udpsock, tcpsock, udp6sock, tcp6sock; 26874462Salfred int xcreated = 0, s; 269109363Smbr int maxrec = RPC_MAXDATASIZE; 27074462Salfred int one = 1; 271126572Sbms int c, r; 272126572Sbms in_port_t svcport = 0; 2731558Srgrimes 27475635Siedowse udp6conf = tcp6conf = NULL; 275126643Smarkm udp6sock = tcp6sock = 0; 27675635Siedowse 27774462Salfred /* Check that another mountd isn't already running. */ 278149433Spjd pfh = pidfile_open(_PATH_MOUNTDPID, 0644, &otherpid); 279149433Spjd if (pfh == NULL) { 280149433Spjd if (errno == EEXIST) 281149433Spjd errx(1, "mountd already running, pid: %d.", otherpid); 282149433Spjd warn("cannot open or create pidfile"); 283149433Spjd } 28474462Salfred 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); 349149433Spjd 350149433Spjd pidfile_write(pfh); 351149433Spjd 35274462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 35374462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 35474462Salfred udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 35574462Salfred tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 35674791Salfred udpconf = getnetconfigent("udp"); 35774791Salfred tcpconf = getnetconfigent("tcp"); 358109363Smbr 359109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 360109363Smbr 36174791Salfred if (!have_v6) 36274791Salfred goto skip_v6; 36374462Salfred udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 36474462Salfred tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 36574462Salfred /* 36674462Salfred * We're doing host-based access checks here, so don't allow 36774462Salfred * v4-in-v6 to confuse things. The kernel will disable it 36874462Salfred * by default on NFS sockets too. 36974462Salfred */ 37074462Salfred if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6, 371117684Srwatson IPV6_V6ONLY, &one, sizeof one) < 0) { 37274462Salfred syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 37374462Salfred exit(1); 37474462Salfred } 37574462Salfred if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6, 376117684Srwatson IPV6_V6ONLY, &one, sizeof one) < 0) { 377117684Srwatson syslog(LOG_ERR, "can't disable v4-in-v6 on TCP socket"); 37874462Salfred exit(1); 37974462Salfred } 38074462Salfred udp6conf = getnetconfigent("udp6"); 38174462Salfred tcp6conf = getnetconfigent("tcp6"); 38274791Salfred 38374791Salfredskip_v6: 38424759Sguido if (!resvport_only) { 38583687Speter if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 38683687Speter &resvport_only, sizeof(resvport_only)) != 0 && 38783687Speter errno != ENOENT) { 38824759Sguido syslog(LOG_ERR, "sysctl: %m"); 38924759Sguido exit(1); 39024759Sguido } 39124330Sguido } 392126572Sbms if (svcport != 0) { 393126572Sbms bzero(&sin, sizeof(struct sockaddr_in)); 394126572Sbms sin.sin_len = sizeof(struct sockaddr_in); 395126572Sbms sin.sin_family = AF_INET; 396126572Sbms sin.sin_port = htons(svcport); 397126572Sbms 398126572Sbms bzero(&sin6, sizeof(struct sockaddr_in6)); 399126572Sbms sin6.sin6_len = sizeof(struct sockaddr_in6); 400126572Sbms sin6.sin6_family = AF_INET6; 401126572Sbms sin6.sin6_port = htons(svcport); 402126572Sbms } 40374462Salfred if (udpsock != -1 && udpconf != NULL) { 404126572Sbms if (svcport != 0) { 405126572Sbms r = bindresvport(udpsock, &sin); 406126572Sbms if (r != 0) { 407126572Sbms syslog(LOG_ERR, "bindresvport: %m"); 408126572Sbms exit(1); 409126572Sbms } 410126572Sbms } else 411126572Sbms (void)bindresvport(udpsock, NULL); 41274462Salfred udptransp = svc_dg_create(udpsock, 0, 0); 41374462Salfred if (udptransp != NULL) { 41474462Salfred if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, 41574462Salfred mntsrv, udpconf)) 41674462Salfred syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service"); 41774462Salfred else 41874462Salfred xcreated++; 41974462Salfred if (!force_v2) { 42074462Salfred if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3, 42174462Salfred mntsrv, udpconf)) 42274462Salfred syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service"); 42374462Salfred else 42474462Salfred xcreated++; 42574462Salfred } 42674462Salfred } else 42774462Salfred syslog(LOG_WARNING, "can't create UDP services"); 42874462Salfred 42974462Salfred } 43074462Salfred if (tcpsock != -1 && tcpconf != NULL) { 431126572Sbms if (svcport != 0) { 432126572Sbms r = bindresvport(tcpsock, &sin); 433126572Sbms if (r != 0) { 434126572Sbms syslog(LOG_ERR, "bindresvport: %m"); 435126572Sbms exit(1); 436126572Sbms } 437126572Sbms } else 438126572Sbms (void)bindresvport(tcpsock, NULL); 43974462Salfred listen(tcpsock, SOMAXCONN); 440109363Smbr tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 44174462Salfred if (tcptransp != NULL) { 44274462Salfred if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1, 44374462Salfred mntsrv, tcpconf)) 44474462Salfred syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service"); 44574462Salfred else 44674462Salfred xcreated++; 44774462Salfred if (!force_v2) { 44874462Salfred if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3, 44974462Salfred mntsrv, tcpconf)) 45074462Salfred syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service"); 45174462Salfred else 45274462Salfred xcreated++; 45374462Salfred } 45474462Salfred } else 45574462Salfred syslog(LOG_WARNING, "can't create TCP service"); 45674462Salfred 45774462Salfred } 45874791Salfred if (have_v6 && udp6sock != -1 && udp6conf != NULL) { 459126572Sbms if (svcport != 0) { 460126572Sbms r = bindresvport_sa(udp6sock, 461126572Sbms (struct sockaddr *)&sin6); 462126572Sbms if (r != 0) { 463126572Sbms syslog(LOG_ERR, "bindresvport_sa: %m"); 464126572Sbms exit(1); 465126572Sbms } 466126572Sbms } else 467126572Sbms (void)bindresvport_sa(udp6sock, NULL); 46874462Salfred udp6transp = svc_dg_create(udp6sock, 0, 0); 46974462Salfred if (udp6transp != NULL) { 47074462Salfred if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, 47174462Salfred mntsrv, udp6conf)) 47274462Salfred syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service"); 47374462Salfred else 47474462Salfred xcreated++; 47574462Salfred if (!force_v2) { 47674462Salfred if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3, 47774462Salfred mntsrv, udp6conf)) 47874462Salfred syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service"); 47974462Salfred else 48074462Salfred xcreated++; 48174462Salfred } 48274462Salfred } else 48374462Salfred syslog(LOG_WARNING, "can't create UDP6 service"); 48474462Salfred 48574462Salfred } 48674791Salfred if (have_v6 && tcp6sock != -1 && tcp6conf != NULL) { 487126572Sbms if (svcport != 0) { 488126572Sbms r = bindresvport_sa(tcp6sock, 489126572Sbms (struct sockaddr *)&sin6); 490126572Sbms if (r != 0) { 491126572Sbms syslog(LOG_ERR, "bindresvport_sa: %m"); 492126572Sbms exit(1); 493126572Sbms } 494126572Sbms } else 495126572Sbms (void)bindresvport_sa(tcp6sock, NULL); 49674462Salfred listen(tcp6sock, SOMAXCONN); 497109363Smbr tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 49874462Salfred if (tcp6transp != NULL) { 49974462Salfred if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1, 50074462Salfred mntsrv, tcp6conf)) 50174462Salfred syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service"); 50274462Salfred else 50374462Salfred xcreated++; 50474462Salfred if (!force_v2) { 50574462Salfred if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3, 50674462Salfred mntsrv, tcp6conf)) 50774462Salfred syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service"); 50874462Salfred else 50974462Salfred xcreated++; 51074462Salfred } 51174462Salfred } else 51274462Salfred syslog(LOG_WARNING, "can't create TCP6 service"); 51374462Salfred 51474462Salfred } 51574462Salfred if (xcreated == 0) { 51674462Salfred syslog(LOG_ERR, "could not create any services"); 5171558Srgrimes exit(1); 5181558Srgrimes } 51975754Siedowse 52075754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 52175754Siedowse for (;;) { 52275754Siedowse if (got_sighup) { 52375754Siedowse get_exportlist(); 52475754Siedowse got_sighup = 0; 52575754Siedowse } 52675754Siedowse readfds = svc_fdset; 52775754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 52875754Siedowse case -1: 52975754Siedowse if (errno == EINTR) 53075754Siedowse continue; 53175754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 53275754Siedowse exit(1); 53375754Siedowse case 0: 53475754Siedowse continue; 53575754Siedowse default: 53675754Siedowse svc_getreqset(&readfds); 53775754Siedowse } 53875754Siedowse } 5391558Srgrimes} 5401558Srgrimes 54137663Scharnierstatic void 54237663Scharnierusage() 54337663Scharnier{ 54437663Scharnier fprintf(stderr, 545126572Sbms "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] " 546126572Sbms "[export_file]\n"); 54737663Scharnier exit(1); 54837663Scharnier} 54937663Scharnier 5501558Srgrimes/* 5511558Srgrimes * The mount rpc service 5521558Srgrimes */ 5531558Srgrimesvoid 5541558Srgrimesmntsrv(rqstp, transp) 5551558Srgrimes struct svc_req *rqstp; 5561558Srgrimes SVCXPRT *transp; 5571558Srgrimes{ 5581558Srgrimes struct exportlist *ep; 5591558Srgrimes struct dirlist *dp; 5609336Sdfr struct fhreturn fhr; 5611558Srgrimes struct stat stb; 5621558Srgrimes struct statfs fsb; 56374462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 56474462Salfred int lookup_failed = 1; 56574462Salfred struct sockaddr *saddr; 5669336Sdfr u_short sport; 56723681Speter char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 56828911Sguido int bad = 0, defset, hostset; 5699336Sdfr sigset_t sighup_mask; 5701558Srgrimes 5719336Sdfr sigemptyset(&sighup_mask); 5729336Sdfr sigaddset(&sighup_mask, SIGHUP); 57374462Salfred saddr = svc_getrpccaller(transp)->buf; 57474462Salfred switch (saddr->sa_family) { 57574462Salfred case AF_INET6: 57675635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 57774462Salfred break; 57874462Salfred case AF_INET: 57975635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 58074462Salfred break; 58174462Salfred default: 58274462Salfred syslog(LOG_ERR, "request from unknown address family"); 58374462Salfred return; 58474462Salfred } 58574462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 58674462Salfred NULL, 0, 0); 58774462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 58874462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 5891558Srgrimes switch (rqstp->rq_proc) { 5901558Srgrimes case NULLPROC: 591121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 59237663Scharnier syslog(LOG_ERR, "can't send reply"); 5931558Srgrimes return; 5941558Srgrimes case RPCMNT_MOUNT: 5959336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 59631656Sguido syslog(LOG_NOTICE, 59731656Sguido "mount request from %s from unprivileged port", 59874462Salfred numerichost); 5991558Srgrimes svcerr_weakauth(transp); 6001558Srgrimes return; 6011558Srgrimes } 602121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 60331656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 60474462Salfred numerichost); 6051558Srgrimes svcerr_decode(transp); 6061558Srgrimes return; 6071558Srgrimes } 6081558Srgrimes 6091558Srgrimes /* 6101558Srgrimes * Get the real pathname and make sure it is a directory 6119336Sdfr * or a regular file if the -r option was specified 6129336Sdfr * and it exists. 6131558Srgrimes */ 61451968Salfred if (realpath(rpcpath, dirpath) == NULL || 6151558Srgrimes stat(dirpath, &stb) < 0 || 6169336Sdfr (!S_ISDIR(stb.st_mode) && 61774462Salfred (dir_only || !S_ISREG(stb.st_mode))) || 6181558Srgrimes statfs(dirpath, &fsb) < 0) { 6191558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 62031656Sguido syslog(LOG_NOTICE, 62137663Scharnier "mount request from %s for non existent path %s", 62274462Salfred numerichost, dirpath); 6231558Srgrimes if (debug) 62437663Scharnier warnx("stat failed on %s", dirpath); 62528911Sguido bad = ENOENT; /* We will send error reply later */ 6261558Srgrimes } 6271558Srgrimes 6281558Srgrimes /* Check in the exports list */ 6299336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 6301558Srgrimes ep = ex_search(&fsb.f_fsid); 6319336Sdfr hostset = defset = 0; 6329336Sdfr if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 6331558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 63474462Salfred chk_host(dp, saddr, &defset, &hostset)) || 63574462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 63674462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 63728911Sguido if (bad) { 638121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 63928911Sguido (caddr_t)&bad)) 64037663Scharnier syslog(LOG_ERR, "can't send reply"); 64128911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 64228911Sguido return; 64328911Sguido } 6449336Sdfr if (hostset & DP_HOSTSET) 6459336Sdfr fhr.fhr_flag = hostset; 6469336Sdfr else 6479336Sdfr fhr.fhr_flag = defset; 6489336Sdfr fhr.fhr_vers = rqstp->rq_vers; 6491558Srgrimes /* Get the file handle */ 65023681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 6519336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 6521558Srgrimes bad = errno; 65337663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 654121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 6551558Srgrimes (caddr_t)&bad)) 65637663Scharnier syslog(LOG_ERR, "can't send reply"); 6579336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 6581558Srgrimes return; 6591558Srgrimes } 660121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 661121556Speter (caddr_t)&fhr)) 66237663Scharnier syslog(LOG_ERR, "can't send reply"); 66374462Salfred if (!lookup_failed) 66474462Salfred add_mlist(host, dirpath); 6651558Srgrimes else 66674462Salfred add_mlist(numerichost, dirpath); 6671558Srgrimes if (debug) 66837663Scharnier warnx("mount successful"); 669121767Speter if (dolog) 67031656Sguido syslog(LOG_NOTICE, 67131656Sguido "mount request succeeded from %s for %s", 67274462Salfred numerichost, dirpath); 67331656Sguido } else { 6741558Srgrimes bad = EACCES; 67531656Sguido syslog(LOG_NOTICE, 67631656Sguido "mount request denied from %s for %s", 67774462Salfred numerichost, dirpath); 67831656Sguido } 67928911Sguido 680121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 681121556Speter (caddr_t)&bad)) 68237663Scharnier syslog(LOG_ERR, "can't send reply"); 6839336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 6841558Srgrimes return; 6851558Srgrimes case RPCMNT_DUMP: 686121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 68737663Scharnier syslog(LOG_ERR, "can't send reply"); 688121767Speter else if (dolog) 68931656Sguido syslog(LOG_NOTICE, 69031656Sguido "dump request succeeded from %s", 69174462Salfred numerichost); 6921558Srgrimes return; 6931558Srgrimes case RPCMNT_UMOUNT: 6949336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 69531656Sguido syslog(LOG_NOTICE, 69631656Sguido "umount request from %s from unprivileged port", 69774462Salfred numerichost); 6981558Srgrimes svcerr_weakauth(transp); 6991558Srgrimes return; 7001558Srgrimes } 701121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 70231656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 70374462Salfred numerichost); 7041558Srgrimes svcerr_decode(transp); 7051558Srgrimes return; 7061558Srgrimes } 70751968Salfred if (realpath(rpcpath, dirpath) == NULL) { 70851968Salfred syslog(LOG_NOTICE, "umount request from %s " 70951968Salfred "for non existent path %s", 71074462Salfred numerichost, dirpath); 71151968Salfred } 712121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 71337663Scharnier syslog(LOG_ERR, "can't send reply"); 71474462Salfred if (!lookup_failed) 71575635Siedowse del_mlist(host, dirpath); 71675635Siedowse del_mlist(numerichost, dirpath); 717121767Speter if (dolog) 71831656Sguido syslog(LOG_NOTICE, 71931656Sguido "umount request succeeded from %s for %s", 72074462Salfred numerichost, dirpath); 7211558Srgrimes return; 7221558Srgrimes case RPCMNT_UMNTALL: 7239336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 72431656Sguido syslog(LOG_NOTICE, 72531656Sguido "umountall request from %s from unprivileged port", 72674462Salfred numerichost); 7271558Srgrimes svcerr_weakauth(transp); 7281558Srgrimes return; 7291558Srgrimes } 730121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 73137663Scharnier syslog(LOG_ERR, "can't send reply"); 73274462Salfred if (!lookup_failed) 73375635Siedowse del_mlist(host, NULL); 73475635Siedowse del_mlist(numerichost, NULL); 735121767Speter if (dolog) 73631656Sguido syslog(LOG_NOTICE, 73731656Sguido "umountall request succeeded from %s", 73874462Salfred numerichost); 7391558Srgrimes return; 7401558Srgrimes case RPCMNT_EXPORT: 741121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 742121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 743121556Speter (caddr_t)NULL)) 744100117Salfred syslog(LOG_ERR, "can't send reply"); 745121767Speter if (dolog) 74631656Sguido syslog(LOG_NOTICE, 74731656Sguido "export request succeeded from %s", 74874462Salfred numerichost); 7491558Srgrimes return; 7501558Srgrimes default: 7511558Srgrimes svcerr_noproc(transp); 7521558Srgrimes return; 7531558Srgrimes } 7541558Srgrimes} 7551558Srgrimes 7561558Srgrimes/* 7571558Srgrimes * Xdr conversion for a dirpath string 7581558Srgrimes */ 7591558Srgrimesint 7601558Srgrimesxdr_dir(xdrsp, dirp) 7611558Srgrimes XDR *xdrsp; 7621558Srgrimes char *dirp; 7631558Srgrimes{ 7641558Srgrimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 7651558Srgrimes} 7661558Srgrimes 7671558Srgrimes/* 7689336Sdfr * Xdr routine to generate file handle reply 7691558Srgrimes */ 7701558Srgrimesint 7719336Sdfrxdr_fhs(xdrsp, cp) 7721558Srgrimes XDR *xdrsp; 7739336Sdfr caddr_t cp; 7741558Srgrimes{ 77592806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 7769336Sdfr u_long ok = 0, len, auth; 7771558Srgrimes 7781558Srgrimes if (!xdr_long(xdrsp, &ok)) 7791558Srgrimes return (0); 7809336Sdfr switch (fhrp->fhr_vers) { 7819336Sdfr case 1: 7829336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 7839336Sdfr case 3: 7849336Sdfr len = NFSX_V3FH; 7859336Sdfr if (!xdr_long(xdrsp, &len)) 7869336Sdfr return (0); 7879336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 7889336Sdfr return (0); 78983653Speter auth = RPCAUTH_UNIX; 7909336Sdfr len = 1; 7919336Sdfr if (!xdr_long(xdrsp, &len)) 7929336Sdfr return (0); 7939336Sdfr return (xdr_long(xdrsp, &auth)); 7949336Sdfr }; 7959336Sdfr return (0); 7961558Srgrimes} 7971558Srgrimes 7981558Srgrimesint 7991558Srgrimesxdr_mlist(xdrsp, cp) 8001558Srgrimes XDR *xdrsp; 8011558Srgrimes caddr_t cp; 8021558Srgrimes{ 8031558Srgrimes struct mountlist *mlp; 8041558Srgrimes int true = 1; 8051558Srgrimes int false = 0; 8061558Srgrimes char *strp; 8071558Srgrimes 8081558Srgrimes mlp = mlhead; 8091558Srgrimes while (mlp) { 8101558Srgrimes if (!xdr_bool(xdrsp, &true)) 8111558Srgrimes return (0); 8121558Srgrimes strp = &mlp->ml_host[0]; 8131558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 8141558Srgrimes return (0); 8151558Srgrimes strp = &mlp->ml_dirp[0]; 8161558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 8171558Srgrimes return (0); 8181558Srgrimes mlp = mlp->ml_next; 8191558Srgrimes } 8201558Srgrimes if (!xdr_bool(xdrsp, &false)) 8211558Srgrimes return (0); 8221558Srgrimes return (1); 8231558Srgrimes} 8241558Srgrimes 8251558Srgrimes/* 8261558Srgrimes * Xdr conversion for export list 8271558Srgrimes */ 8281558Srgrimesint 829100117Salfredxdr_explist_common(xdrsp, cp, brief) 8301558Srgrimes XDR *xdrsp; 8311558Srgrimes caddr_t cp; 832100117Salfred int brief; 8331558Srgrimes{ 8341558Srgrimes struct exportlist *ep; 8351558Srgrimes int false = 0; 8369336Sdfr int putdef; 8379336Sdfr sigset_t sighup_mask; 8381558Srgrimes 8399336Sdfr sigemptyset(&sighup_mask); 8409336Sdfr sigaddset(&sighup_mask, SIGHUP); 8419336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 8421558Srgrimes ep = exphead; 8431558Srgrimes while (ep) { 8441558Srgrimes putdef = 0; 845100117Salfred if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 846100117Salfred &putdef, brief)) 8471558Srgrimes goto errout; 8481558Srgrimes if (ep->ex_defdir && putdef == 0 && 8491558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 850100117Salfred &putdef, brief)) 8511558Srgrimes goto errout; 8521558Srgrimes ep = ep->ex_next; 8531558Srgrimes } 8549336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8551558Srgrimes if (!xdr_bool(xdrsp, &false)) 8561558Srgrimes return (0); 8571558Srgrimes return (1); 8581558Srgrimeserrout: 8599336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8601558Srgrimes return (0); 8611558Srgrimes} 8621558Srgrimes 8631558Srgrimes/* 8641558Srgrimes * Called from xdr_explist() to traverse the tree and export the 8651558Srgrimes * directory paths. 8661558Srgrimes */ 8671558Srgrimesint 868100117Salfredput_exlist(dp, xdrsp, adp, putdefp, brief) 8691558Srgrimes struct dirlist *dp; 8701558Srgrimes XDR *xdrsp; 8711558Srgrimes struct dirlist *adp; 8721558Srgrimes int *putdefp; 873100117Salfred int brief; 8741558Srgrimes{ 8751558Srgrimes struct grouplist *grp; 8761558Srgrimes struct hostlist *hp; 8771558Srgrimes int true = 1; 8781558Srgrimes int false = 0; 8791558Srgrimes int gotalldir = 0; 8801558Srgrimes char *strp; 8811558Srgrimes 8821558Srgrimes if (dp) { 883100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 8841558Srgrimes return (1); 8851558Srgrimes if (!xdr_bool(xdrsp, &true)) 8861558Srgrimes return (1); 8871558Srgrimes strp = dp->dp_dirp; 8881558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 8891558Srgrimes return (1); 8901558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 8911558Srgrimes gotalldir = 1; 8921558Srgrimes *putdefp = 1; 8931558Srgrimes } 894100117Salfred if (brief) { 895100117Salfred if (!xdr_bool(xdrsp, &true)) 896100117Salfred return (1); 897100117Salfred strp = "(...)"; 898100117Salfred if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 899100117Salfred return (1); 900100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 9011558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 9021558Srgrimes hp = dp->dp_hosts; 9031558Srgrimes while (hp) { 9041558Srgrimes grp = hp->ht_grp; 9051558Srgrimes if (grp->gr_type == GT_HOST) { 9061558Srgrimes if (!xdr_bool(xdrsp, &true)) 9071558Srgrimes return (1); 90874462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 9098871Srgrimes if (!xdr_string(xdrsp, &strp, 9101558Srgrimes RPCMNT_NAMELEN)) 9111558Srgrimes return (1); 9121558Srgrimes } else if (grp->gr_type == GT_NET) { 9131558Srgrimes if (!xdr_bool(xdrsp, &true)) 9141558Srgrimes return (1); 9151558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 9168871Srgrimes if (!xdr_string(xdrsp, &strp, 9171558Srgrimes RPCMNT_NAMELEN)) 9181558Srgrimes return (1); 9191558Srgrimes } 9201558Srgrimes hp = hp->ht_next; 9211558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 9221558Srgrimes hp = adp->dp_hosts; 9231558Srgrimes gotalldir = 0; 9241558Srgrimes } 9251558Srgrimes } 9261558Srgrimes } 9271558Srgrimes if (!xdr_bool(xdrsp, &false)) 9281558Srgrimes return (1); 929100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 9301558Srgrimes return (1); 9311558Srgrimes } 9321558Srgrimes return (0); 9331558Srgrimes} 9341558Srgrimes 935100117Salfredint 936100117Salfredxdr_explist(xdrsp, cp) 937100117Salfred XDR *xdrsp; 938100117Salfred caddr_t cp; 939100117Salfred{ 940100117Salfred 941100117Salfred return xdr_explist_common(xdrsp, cp, 0); 942100117Salfred} 943100117Salfred 944100117Salfredint 945100117Salfredxdr_explist_brief(xdrsp, cp) 946100117Salfred XDR *xdrsp; 947100117Salfred caddr_t cp; 948100117Salfred{ 949100117Salfred 950100117Salfred return xdr_explist_common(xdrsp, cp, 1); 951100117Salfred} 952100117Salfred 95396622Siedowsechar *line; 95496622Siedowseint linesize; 9551558SrgrimesFILE *exp_file; 9561558Srgrimes 9571558Srgrimes/* 9581558Srgrimes * Get the export list 9591558Srgrimes */ 9601558Srgrimesvoid 9611558Srgrimesget_exportlist() 9621558Srgrimes{ 9631558Srgrimes struct exportlist *ep, *ep2; 9641558Srgrimes struct grouplist *grp, *tgrp; 9651558Srgrimes struct exportlist **epp; 9661558Srgrimes struct dirlist *dirhead; 9671558Srgrimes struct statfs fsb, *fsp; 96872650Sgreen struct xucred anon; 9691558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 9701558Srgrimes int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 9711558Srgrimes 97251968Salfred dirp = NULL; 97351968Salfred dirplen = 0; 97451968Salfred 9751558Srgrimes /* 9761558Srgrimes * First, get rid of the old list 9771558Srgrimes */ 9781558Srgrimes ep = exphead; 9791558Srgrimes while (ep) { 9801558Srgrimes ep2 = ep; 9811558Srgrimes ep = ep->ex_next; 9821558Srgrimes free_exp(ep2); 9831558Srgrimes } 9841558Srgrimes exphead = (struct exportlist *)NULL; 9851558Srgrimes 9861558Srgrimes grp = grphead; 9871558Srgrimes while (grp) { 9881558Srgrimes tgrp = grp; 9891558Srgrimes grp = grp->gr_next; 9901558Srgrimes free_grp(tgrp); 9911558Srgrimes } 9921558Srgrimes grphead = (struct grouplist *)NULL; 9931558Srgrimes 9941558Srgrimes /* 9951558Srgrimes * And delete exports that are in the kernel for all local 99696707Strhodes * filesystems. 99796707Strhodes * XXX: Should know how to handle all local exportable filesystems 99823681Speter * instead of just "ufs". 9991558Srgrimes */ 10001558Srgrimes num = getmntinfo(&fsp, MNT_NOWAIT); 10011558Srgrimes for (i = 0; i < num; i++) { 10021558Srgrimes union { 10031558Srgrimes struct ufs_args ua; 10041558Srgrimes struct iso_args ia; 10059336Sdfr struct msdosfs_args da; 100654093Ssemenu struct ntfs_args na; 10071558Srgrimes } targs; 10081558Srgrimes 100977435Sphk if (!strcmp(fsp->f_fstypename, "ufs") || 101077577Sru !strcmp(fsp->f_fstypename, "msdosfs") || 101154093Ssemenu !strcmp(fsp->f_fstypename, "ntfs") || 101223681Speter !strcmp(fsp->f_fstypename, "cd9660")) { 1013138680Sphk bzero(&targs, sizeof targs); 10149336Sdfr targs.ua.fspec = NULL; 10159336Sdfr targs.ua.export.ex_flags = MNT_DELEXPORT; 10169336Sdfr if (mount(fsp->f_fstypename, fsp->f_mntonname, 101777405Siedowse fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0 && 101877405Siedowse errno != ENOENT) 101977405Siedowse syslog(LOG_ERR, 102077405Siedowse "can't delete exports for %s: %m", 102174462Salfred fsp->f_mntonname); 10221558Srgrimes } 10231558Srgrimes fsp++; 10241558Srgrimes } 10251558Srgrimes 10261558Srgrimes /* 10271558Srgrimes * Read in the exports file and build the list, calling 10281558Srgrimes * mount() as we go along to push the export rules into the kernel. 10291558Srgrimes */ 10301558Srgrimes if ((exp_file = fopen(exname, "r")) == NULL) { 103137663Scharnier syslog(LOG_ERR, "can't open %s", exname); 10321558Srgrimes exit(2); 10331558Srgrimes } 10341558Srgrimes dirhead = (struct dirlist *)NULL; 10351558Srgrimes while (get_line()) { 10361558Srgrimes if (debug) 103737663Scharnier warnx("got line %s", line); 10381558Srgrimes cp = line; 10391558Srgrimes nextfield(&cp, &endcp); 10401558Srgrimes if (*cp == '#') 10411558Srgrimes goto nextline; 10421558Srgrimes 10431558Srgrimes /* 10441558Srgrimes * Set defaults. 10451558Srgrimes */ 10461558Srgrimes has_host = FALSE; 10471558Srgrimes anon = def_anon; 10481558Srgrimes exflags = MNT_EXPORTED; 10491558Srgrimes got_nondir = 0; 10501558Srgrimes opt_flags = 0; 10511558Srgrimes ep = (struct exportlist *)NULL; 10521558Srgrimes 10531558Srgrimes /* 10541558Srgrimes * Create new exports list entry 10551558Srgrimes */ 10561558Srgrimes len = endcp-cp; 10571558Srgrimes tgrp = grp = get_grp(); 10581558Srgrimes while (len > 0) { 10591558Srgrimes if (len > RPCMNT_NAMELEN) { 10601558Srgrimes getexp_err(ep, tgrp); 10611558Srgrimes goto nextline; 10621558Srgrimes } 10631558Srgrimes if (*cp == '-') { 10641558Srgrimes if (ep == (struct exportlist *)NULL) { 10651558Srgrimes getexp_err(ep, tgrp); 10661558Srgrimes goto nextline; 10671558Srgrimes } 10681558Srgrimes if (debug) 106937663Scharnier warnx("doing opt %s", cp); 10701558Srgrimes got_nondir = 1; 10711558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 10721558Srgrimes &exflags, &anon)) { 10731558Srgrimes getexp_err(ep, tgrp); 10741558Srgrimes goto nextline; 10751558Srgrimes } 10761558Srgrimes } else if (*cp == '/') { 10771558Srgrimes savedc = *endcp; 10781558Srgrimes *endcp = '\0'; 10791558Srgrimes if (check_dirpath(cp) && 10801558Srgrimes statfs(cp, &fsb) >= 0) { 10811558Srgrimes if (got_nondir) { 108237663Scharnier syslog(LOG_ERR, "dirs must be first"); 10831558Srgrimes getexp_err(ep, tgrp); 10841558Srgrimes goto nextline; 10851558Srgrimes } 10861558Srgrimes if (ep) { 10871558Srgrimes if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 10881558Srgrimes ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 10891558Srgrimes getexp_err(ep, tgrp); 10901558Srgrimes goto nextline; 10911558Srgrimes } 10921558Srgrimes } else { 10931558Srgrimes /* 10941558Srgrimes * See if this directory is already 10951558Srgrimes * in the list. 10961558Srgrimes */ 10971558Srgrimes ep = ex_search(&fsb.f_fsid); 10981558Srgrimes if (ep == (struct exportlist *)NULL) { 10991558Srgrimes ep = get_exp(); 11001558Srgrimes ep->ex_fs = fsb.f_fsid; 11011558Srgrimes ep->ex_fsdir = (char *) 11021558Srgrimes malloc(strlen(fsb.f_mntonname) + 1); 11031558Srgrimes if (ep->ex_fsdir) 11041558Srgrimes strcpy(ep->ex_fsdir, 11051558Srgrimes fsb.f_mntonname); 11061558Srgrimes else 11071558Srgrimes out_of_mem(); 11081558Srgrimes if (debug) 110974462Salfred warnx("making new ep fs=0x%x,0x%x", 111074462Salfred fsb.f_fsid.val[0], 111174462Salfred fsb.f_fsid.val[1]); 11121558Srgrimes } else if (debug) 111337663Scharnier warnx("found ep fs=0x%x,0x%x", 11141558Srgrimes fsb.f_fsid.val[0], 11151558Srgrimes fsb.f_fsid.val[1]); 11161558Srgrimes } 11171558Srgrimes 11181558Srgrimes /* 11191558Srgrimes * Add dirpath to export mount point. 11201558Srgrimes */ 11211558Srgrimes dirp = add_expdir(&dirhead, cp, len); 11221558Srgrimes dirplen = len; 11231558Srgrimes } else { 11241558Srgrimes getexp_err(ep, tgrp); 11251558Srgrimes goto nextline; 11261558Srgrimes } 11271558Srgrimes *endcp = savedc; 11281558Srgrimes } else { 11291558Srgrimes savedc = *endcp; 11301558Srgrimes *endcp = '\0'; 11311558Srgrimes got_nondir = 1; 11321558Srgrimes if (ep == (struct exportlist *)NULL) { 11331558Srgrimes getexp_err(ep, tgrp); 11341558Srgrimes goto nextline; 11351558Srgrimes } 11361558Srgrimes 11371558Srgrimes /* 11381558Srgrimes * Get the host or netgroup. 11391558Srgrimes */ 11401558Srgrimes setnetgrent(cp); 11411558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 11421558Srgrimes do { 11431558Srgrimes if (has_host) { 11441558Srgrimes grp->gr_next = get_grp(); 11451558Srgrimes grp = grp->gr_next; 11461558Srgrimes } 11471558Srgrimes if (netgrp) { 114837003Sjoerg if (hst == 0) { 114937663Scharnier syslog(LOG_ERR, 115037663Scharnier "null hostname in netgroup %s, skipping", cp); 115137004Sjoerg grp->gr_type = GT_IGNORE; 115237003Sjoerg } else if (get_host(hst, grp, tgrp)) { 115337663Scharnier syslog(LOG_ERR, 115437663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 115529317Sjlemon grp->gr_type = GT_IGNORE; 11561558Srgrimes } 11577401Swpaul } else if (get_host(cp, grp, tgrp)) { 115837663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 115929317Sjlemon grp->gr_type = GT_IGNORE; 11601558Srgrimes } 11611558Srgrimes has_host = TRUE; 11621558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 11631558Srgrimes endnetgrent(); 11641558Srgrimes *endcp = savedc; 11651558Srgrimes } 11661558Srgrimes cp = endcp; 11671558Srgrimes nextfield(&cp, &endcp); 11681558Srgrimes len = endcp - cp; 11691558Srgrimes } 11701558Srgrimes if (check_options(dirhead)) { 11711558Srgrimes getexp_err(ep, tgrp); 11721558Srgrimes goto nextline; 11731558Srgrimes } 11741558Srgrimes if (!has_host) { 117575641Siedowse grp->gr_type = GT_DEFAULT; 11761558Srgrimes if (debug) 117737663Scharnier warnx("adding a default entry"); 11781558Srgrimes 11791558Srgrimes /* 11801558Srgrimes * Don't allow a network export coincide with a list of 11811558Srgrimes * host(s) on the same line. 11821558Srgrimes */ 11831558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 118475801Siedowse syslog(LOG_ERR, "network/host conflict"); 11851558Srgrimes getexp_err(ep, tgrp); 11861558Srgrimes goto nextline; 118729317Sjlemon 118874462Salfred /* 118974462Salfred * If an export list was specified on this line, make sure 119029317Sjlemon * that we have at least one valid entry, otherwise skip it. 119129317Sjlemon */ 119229317Sjlemon } else { 119329317Sjlemon grp = tgrp; 119474462Salfred while (grp && grp->gr_type == GT_IGNORE) 119529317Sjlemon grp = grp->gr_next; 119629317Sjlemon if (! grp) { 119729317Sjlemon getexp_err(ep, tgrp); 119829317Sjlemon goto nextline; 119929317Sjlemon } 12001558Srgrimes } 12011558Srgrimes 12021558Srgrimes /* 12031558Srgrimes * Loop through hosts, pushing the exports into the kernel. 12041558Srgrimes * After loop, tgrp points to the start of the list and 12051558Srgrimes * grp points to the last entry in the list. 12061558Srgrimes */ 12071558Srgrimes grp = tgrp; 12081558Srgrimes do { 120975635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 121075635Siedowse &fsb)) { 121175635Siedowse getexp_err(ep, tgrp); 121275635Siedowse goto nextline; 121375635Siedowse } 12141558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 12151558Srgrimes 12161558Srgrimes /* 12171558Srgrimes * Success. Update the data structures. 12181558Srgrimes */ 12191558Srgrimes if (has_host) { 12209336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 12211558Srgrimes grp->gr_next = grphead; 12221558Srgrimes grphead = tgrp; 12231558Srgrimes } else { 12241558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 12259336Sdfr opt_flags); 12261558Srgrimes free_grp(grp); 12271558Srgrimes } 12281558Srgrimes dirhead = (struct dirlist *)NULL; 12291558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 12301558Srgrimes ep2 = exphead; 12311558Srgrimes epp = &exphead; 12321558Srgrimes 12331558Srgrimes /* 12341558Srgrimes * Insert in the list in alphabetical order. 12351558Srgrimes */ 12361558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 12371558Srgrimes epp = &ep2->ex_next; 12381558Srgrimes ep2 = ep2->ex_next; 12391558Srgrimes } 12401558Srgrimes if (ep2) 12411558Srgrimes ep->ex_next = ep2; 12421558Srgrimes *epp = ep; 12431558Srgrimes ep->ex_flag |= EX_LINKED; 12441558Srgrimes } 12451558Srgrimesnextline: 12461558Srgrimes if (dirhead) { 12471558Srgrimes free_dir(dirhead); 12481558Srgrimes dirhead = (struct dirlist *)NULL; 12491558Srgrimes } 12501558Srgrimes } 12511558Srgrimes fclose(exp_file); 12521558Srgrimes} 12531558Srgrimes 12541558Srgrimes/* 12551558Srgrimes * Allocate an export list element 12561558Srgrimes */ 12571558Srgrimesstruct exportlist * 12581558Srgrimesget_exp() 12591558Srgrimes{ 12601558Srgrimes struct exportlist *ep; 12611558Srgrimes 12621558Srgrimes ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 12631558Srgrimes if (ep == (struct exportlist *)NULL) 12641558Srgrimes out_of_mem(); 126523681Speter memset(ep, 0, sizeof(struct exportlist)); 12661558Srgrimes return (ep); 12671558Srgrimes} 12681558Srgrimes 12691558Srgrimes/* 12701558Srgrimes * Allocate a group list element 12711558Srgrimes */ 12721558Srgrimesstruct grouplist * 12731558Srgrimesget_grp() 12741558Srgrimes{ 12751558Srgrimes struct grouplist *gp; 12761558Srgrimes 12771558Srgrimes gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 12781558Srgrimes if (gp == (struct grouplist *)NULL) 12791558Srgrimes out_of_mem(); 128023681Speter memset(gp, 0, sizeof(struct grouplist)); 12811558Srgrimes return (gp); 12821558Srgrimes} 12831558Srgrimes 12841558Srgrimes/* 12851558Srgrimes * Clean up upon an error in get_exportlist(). 12861558Srgrimes */ 12871558Srgrimesvoid 12881558Srgrimesgetexp_err(ep, grp) 12891558Srgrimes struct exportlist *ep; 12901558Srgrimes struct grouplist *grp; 12911558Srgrimes{ 12921558Srgrimes struct grouplist *tgrp; 12931558Srgrimes 1294100336Sjoerg if (!(opt_flags & OP_QUIET)) 1295100336Sjoerg syslog(LOG_ERR, "bad exports list line %s", line); 12961558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 12971558Srgrimes free_exp(ep); 12981558Srgrimes while (grp) { 12991558Srgrimes tgrp = grp; 13001558Srgrimes grp = grp->gr_next; 13011558Srgrimes free_grp(tgrp); 13021558Srgrimes } 13031558Srgrimes} 13041558Srgrimes 13051558Srgrimes/* 13061558Srgrimes * Search the export list for a matching fs. 13071558Srgrimes */ 13081558Srgrimesstruct exportlist * 13091558Srgrimesex_search(fsid) 13101558Srgrimes fsid_t *fsid; 13111558Srgrimes{ 13121558Srgrimes struct exportlist *ep; 13131558Srgrimes 13141558Srgrimes ep = exphead; 13151558Srgrimes while (ep) { 13161558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 13171558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 13181558Srgrimes return (ep); 13191558Srgrimes ep = ep->ex_next; 13201558Srgrimes } 13211558Srgrimes return (ep); 13221558Srgrimes} 13231558Srgrimes 13241558Srgrimes/* 13251558Srgrimes * Add a directory path to the list. 13261558Srgrimes */ 13271558Srgrimeschar * 13281558Srgrimesadd_expdir(dpp, cp, len) 13291558Srgrimes struct dirlist **dpp; 13301558Srgrimes char *cp; 13311558Srgrimes int len; 13321558Srgrimes{ 13331558Srgrimes struct dirlist *dp; 13341558Srgrimes 13351558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 133637663Scharnier if (dp == (struct dirlist *)NULL) 133737663Scharnier out_of_mem(); 13381558Srgrimes dp->dp_left = *dpp; 13391558Srgrimes dp->dp_right = (struct dirlist *)NULL; 13401558Srgrimes dp->dp_flag = 0; 13411558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 13421558Srgrimes strcpy(dp->dp_dirp, cp); 13431558Srgrimes *dpp = dp; 13441558Srgrimes return (dp->dp_dirp); 13451558Srgrimes} 13461558Srgrimes 13471558Srgrimes/* 13481558Srgrimes * Hang the dir list element off the dirpath binary tree as required 13491558Srgrimes * and update the entry for host. 13501558Srgrimes */ 13511558Srgrimesvoid 13529336Sdfrhang_dirp(dp, grp, ep, flags) 13531558Srgrimes struct dirlist *dp; 13541558Srgrimes struct grouplist *grp; 13551558Srgrimes struct exportlist *ep; 13569336Sdfr int flags; 13571558Srgrimes{ 13581558Srgrimes struct hostlist *hp; 13591558Srgrimes struct dirlist *dp2; 13601558Srgrimes 13619336Sdfr if (flags & OP_ALLDIRS) { 13621558Srgrimes if (ep->ex_defdir) 13631558Srgrimes free((caddr_t)dp); 13641558Srgrimes else 13651558Srgrimes ep->ex_defdir = dp; 13669336Sdfr if (grp == (struct grouplist *)NULL) { 13671558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 13689336Sdfr } else while (grp) { 13691558Srgrimes hp = get_ht(); 13701558Srgrimes hp->ht_grp = grp; 13711558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 13721558Srgrimes ep->ex_defdir->dp_hosts = hp; 13731558Srgrimes grp = grp->gr_next; 13741558Srgrimes } 13751558Srgrimes } else { 13761558Srgrimes 13771558Srgrimes /* 137837663Scharnier * Loop through the directories adding them to the tree. 13791558Srgrimes */ 13801558Srgrimes while (dp) { 13811558Srgrimes dp2 = dp->dp_left; 13829336Sdfr add_dlist(&ep->ex_dirl, dp, grp, flags); 13831558Srgrimes dp = dp2; 13841558Srgrimes } 13851558Srgrimes } 13861558Srgrimes} 13871558Srgrimes 13881558Srgrimes/* 13891558Srgrimes * Traverse the binary tree either updating a node that is already there 13901558Srgrimes * for the new directory or adding the new node. 13911558Srgrimes */ 13921558Srgrimesvoid 13939336Sdfradd_dlist(dpp, newdp, grp, flags) 13941558Srgrimes struct dirlist **dpp; 13951558Srgrimes struct dirlist *newdp; 13961558Srgrimes struct grouplist *grp; 13979336Sdfr int flags; 13981558Srgrimes{ 13991558Srgrimes struct dirlist *dp; 14001558Srgrimes struct hostlist *hp; 14011558Srgrimes int cmp; 14021558Srgrimes 14031558Srgrimes dp = *dpp; 14041558Srgrimes if (dp) { 14051558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 14061558Srgrimes if (cmp > 0) { 14079336Sdfr add_dlist(&dp->dp_left, newdp, grp, flags); 14081558Srgrimes return; 14091558Srgrimes } else if (cmp < 0) { 14109336Sdfr add_dlist(&dp->dp_right, newdp, grp, flags); 14111558Srgrimes return; 14121558Srgrimes } else 14131558Srgrimes free((caddr_t)newdp); 14141558Srgrimes } else { 14151558Srgrimes dp = newdp; 14161558Srgrimes dp->dp_left = (struct dirlist *)NULL; 14171558Srgrimes *dpp = dp; 14181558Srgrimes } 14191558Srgrimes if (grp) { 14201558Srgrimes 14211558Srgrimes /* 14221558Srgrimes * Hang all of the host(s) off of the directory point. 14231558Srgrimes */ 14241558Srgrimes do { 14251558Srgrimes hp = get_ht(); 14261558Srgrimes hp->ht_grp = grp; 14271558Srgrimes hp->ht_next = dp->dp_hosts; 14281558Srgrimes dp->dp_hosts = hp; 14291558Srgrimes grp = grp->gr_next; 14301558Srgrimes } while (grp); 14319336Sdfr } else { 14321558Srgrimes dp->dp_flag |= DP_DEFSET; 14339336Sdfr } 14341558Srgrimes} 14351558Srgrimes 14361558Srgrimes/* 14371558Srgrimes * Search for a dirpath on the export point. 14381558Srgrimes */ 14391558Srgrimesstruct dirlist * 144074462Salfreddirp_search(dp, dirp) 14411558Srgrimes struct dirlist *dp; 144274462Salfred char *dirp; 14431558Srgrimes{ 14441558Srgrimes int cmp; 14451558Srgrimes 14461558Srgrimes if (dp) { 144774462Salfred cmp = strcmp(dp->dp_dirp, dirp); 14481558Srgrimes if (cmp > 0) 144974462Salfred return (dirp_search(dp->dp_left, dirp)); 14501558Srgrimes else if (cmp < 0) 145174462Salfred return (dirp_search(dp->dp_right, dirp)); 14521558Srgrimes else 14531558Srgrimes return (dp); 14541558Srgrimes } 14551558Srgrimes return (dp); 14561558Srgrimes} 14571558Srgrimes 14581558Srgrimes/* 14591558Srgrimes * Scan for a host match in a directory tree. 14601558Srgrimes */ 14611558Srgrimesint 14629336Sdfrchk_host(dp, saddr, defsetp, hostsetp) 14631558Srgrimes struct dirlist *dp; 146474462Salfred struct sockaddr *saddr; 14651558Srgrimes int *defsetp; 14669336Sdfr int *hostsetp; 14671558Srgrimes{ 14681558Srgrimes struct hostlist *hp; 14691558Srgrimes struct grouplist *grp; 147074462Salfred struct addrinfo *ai; 14711558Srgrimes 14721558Srgrimes if (dp) { 14731558Srgrimes if (dp->dp_flag & DP_DEFSET) 14749336Sdfr *defsetp = dp->dp_flag; 14751558Srgrimes hp = dp->dp_hosts; 14761558Srgrimes while (hp) { 14771558Srgrimes grp = hp->ht_grp; 14781558Srgrimes switch (grp->gr_type) { 14791558Srgrimes case GT_HOST: 148074462Salfred ai = grp->gr_ptr.gt_addrinfo; 148174462Salfred for (; ai; ai = ai->ai_next) { 148275801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 148374462Salfred *hostsetp = 148474462Salfred (hp->ht_flag | DP_HOSTSET); 148574462Salfred return (1); 148674462Salfred } 14879336Sdfr } 148875801Siedowse break; 14891558Srgrimes case GT_NET: 149075801Siedowse if (!sacmp(saddr, (struct sockaddr *) 149175801Siedowse &grp->gr_ptr.gt_net.nt_net, 149275801Siedowse (struct sockaddr *) 149375801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 149474462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 149574462Salfred return (1); 149674462Salfred } 149775801Siedowse break; 149875801Siedowse } 14991558Srgrimes hp = hp->ht_next; 15001558Srgrimes } 15011558Srgrimes } 15021558Srgrimes return (0); 15031558Srgrimes} 15041558Srgrimes 15051558Srgrimes/* 15061558Srgrimes * Scan tree for a host that matches the address. 15071558Srgrimes */ 15081558Srgrimesint 15091558Srgrimesscan_tree(dp, saddr) 15101558Srgrimes struct dirlist *dp; 151174462Salfred struct sockaddr *saddr; 15121558Srgrimes{ 15139336Sdfr int defset, hostset; 15141558Srgrimes 15151558Srgrimes if (dp) { 15161558Srgrimes if (scan_tree(dp->dp_left, saddr)) 15171558Srgrimes return (1); 15189336Sdfr if (chk_host(dp, saddr, &defset, &hostset)) 15191558Srgrimes return (1); 15201558Srgrimes if (scan_tree(dp->dp_right, saddr)) 15211558Srgrimes return (1); 15221558Srgrimes } 15231558Srgrimes return (0); 15241558Srgrimes} 15251558Srgrimes 15261558Srgrimes/* 15271558Srgrimes * Traverse the dirlist tree and free it up. 15281558Srgrimes */ 15291558Srgrimesvoid 15301558Srgrimesfree_dir(dp) 15311558Srgrimes struct dirlist *dp; 15321558Srgrimes{ 15331558Srgrimes 15341558Srgrimes if (dp) { 15351558Srgrimes free_dir(dp->dp_left); 15361558Srgrimes free_dir(dp->dp_right); 15371558Srgrimes free_host(dp->dp_hosts); 15381558Srgrimes free((caddr_t)dp); 15391558Srgrimes } 15401558Srgrimes} 15411558Srgrimes 15421558Srgrimes/* 15431558Srgrimes * Parse the option string and update fields. 15441558Srgrimes * Option arguments may either be -<option>=<value> or 15451558Srgrimes * -<option> <value> 15461558Srgrimes */ 15471558Srgrimesint 15481558Srgrimesdo_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 15491558Srgrimes char **cpp, **endcpp; 15501558Srgrimes struct exportlist *ep; 15511558Srgrimes struct grouplist *grp; 15521558Srgrimes int *has_hostp; 15531558Srgrimes int *exflagsp; 155472650Sgreen struct xucred *cr; 15551558Srgrimes{ 15561558Srgrimes char *cpoptarg, *cpoptend; 15571558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 15581558Srgrimes int allflag, usedarg; 15591558Srgrimes 156051968Salfred savedc2 = '\0'; 15611558Srgrimes cpopt = *cpp; 15621558Srgrimes cpopt++; 15631558Srgrimes cp = *endcpp; 15641558Srgrimes savedc = *cp; 15651558Srgrimes *cp = '\0'; 15661558Srgrimes while (cpopt && *cpopt) { 15671558Srgrimes allflag = 1; 15681558Srgrimes usedarg = -2; 156937663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 15701558Srgrimes *cpoptend++ = '\0'; 157137663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 15721558Srgrimes *cpoptarg++ = '\0'; 15731558Srgrimes } else { 157437663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 15751558Srgrimes *cpoptarg++ = '\0'; 15761558Srgrimes else { 15771558Srgrimes *cp = savedc; 15781558Srgrimes nextfield(&cp, &endcp); 15791558Srgrimes **endcpp = '\0'; 15801558Srgrimes if (endcp > cp && *cp != '-') { 15811558Srgrimes cpoptarg = cp; 15821558Srgrimes savedc2 = *endcp; 15831558Srgrimes *endcp = '\0'; 15841558Srgrimes usedarg = 0; 15851558Srgrimes } 15861558Srgrimes } 15871558Srgrimes } 15881558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 15891558Srgrimes *exflagsp |= MNT_EXRDONLY; 15901558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 15911558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 15921558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 15931558Srgrimes usedarg++; 15941558Srgrimes parsecred(cpoptarg, cr); 15951558Srgrimes if (allflag == 0) { 15961558Srgrimes *exflagsp |= MNT_EXPORTANON; 15971558Srgrimes opt_flags |= OP_MAPALL; 15981558Srgrimes } else 15991558Srgrimes opt_flags |= OP_MAPROOT; 16001558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 160175801Siedowse !strcmp(cpopt, "m"))) { 16021558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 160337663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 16041558Srgrimes return (1); 16051558Srgrimes } 16061558Srgrimes usedarg++; 16071558Srgrimes opt_flags |= OP_MASK; 16081558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 16091558Srgrimes !strcmp(cpopt, "n"))) { 161074462Salfred if (strchr(cpoptarg, '/') != NULL) { 161174462Salfred if (debug) 161274462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 161374462Salfred opt_flags |= OP_MASKLEN; 161474462Salfred } 16151558Srgrimes if (grp->gr_type != GT_NULL) { 161637663Scharnier syslog(LOG_ERR, "network/host conflict"); 16171558Srgrimes return (1); 16181558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 161937663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 16201558Srgrimes return (1); 16211558Srgrimes } 16221558Srgrimes grp->gr_type = GT_NET; 16231558Srgrimes *has_hostp = 1; 16241558Srgrimes usedarg++; 16251558Srgrimes opt_flags |= OP_NET; 16261558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 16271558Srgrimes opt_flags |= OP_ALLDIRS; 162827447Sdfr } else if (!strcmp(cpopt, "public")) { 162927447Sdfr *exflagsp |= MNT_EXPUBLIC; 163027447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 163127447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 163227447Sdfr opt_flags |= OP_MAPALL; 163327447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 163427447Sdfr ep->ex_indexfile = strdup(cpoptarg); 1635100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 1636100336Sjoerg opt_flags |= OP_QUIET; 16371558Srgrimes } else { 163837663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 16391558Srgrimes return (1); 16401558Srgrimes } 16411558Srgrimes if (usedarg >= 0) { 16421558Srgrimes *endcp = savedc2; 16431558Srgrimes **endcpp = savedc; 16441558Srgrimes if (usedarg > 0) { 16451558Srgrimes *cpp = cp; 16461558Srgrimes *endcpp = endcp; 16471558Srgrimes } 16481558Srgrimes return (0); 16491558Srgrimes } 16501558Srgrimes cpopt = cpoptend; 16511558Srgrimes } 16521558Srgrimes **endcpp = savedc; 16531558Srgrimes return (0); 16541558Srgrimes} 16551558Srgrimes 16561558Srgrimes/* 16571558Srgrimes * Translate a character string to the corresponding list of network 16581558Srgrimes * addresses for a hostname. 16591558Srgrimes */ 16601558Srgrimesint 16617401Swpaulget_host(cp, grp, tgrp) 16621558Srgrimes char *cp; 16631558Srgrimes struct grouplist *grp; 16647401Swpaul struct grouplist *tgrp; 16651558Srgrimes{ 16667401Swpaul struct grouplist *checkgrp; 166775635Siedowse struct addrinfo *ai, *tai, hints; 166874462Salfred int ecode; 166974462Salfred char host[NI_MAXHOST]; 16701558Srgrimes 167174462Salfred if (grp->gr_type != GT_NULL) { 167274462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 16731558Srgrimes return (1); 16741558Srgrimes } 167574462Salfred memset(&hints, 0, sizeof hints); 167674462Salfred hints.ai_flags = AI_CANONNAME; 167774462Salfred hints.ai_protocol = IPPROTO_UDP; 167874462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 167974462Salfred if (ecode != 0) { 168075635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 168174462Salfred return 1; 168274462Salfred } 168374462Salfred grp->gr_ptr.gt_addrinfo = ai; 168474462Salfred while (ai != NULL) { 168574462Salfred if (ai->ai_canonname == NULL) { 168674462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 1687146187Sume sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 168874462Salfred strlcpy(host, "?", sizeof(host)); 168974462Salfred ai->ai_canonname = strdup(host); 169074462Salfred ai->ai_flags |= AI_CANONNAME; 169175641Siedowse } 169274462Salfred if (debug) 169375635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 169475635Siedowse /* 169575635Siedowse * Sanity check: make sure we don't already have an entry 169675635Siedowse * for this host in the grouplist. 169775635Siedowse */ 169875635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 169975635Siedowse checkgrp = checkgrp->gr_next) { 170075635Siedowse if (checkgrp->gr_type != GT_HOST) 170175635Siedowse continue; 170275635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 170375635Siedowse tai = tai->ai_next) { 170475801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 170575635Siedowse continue; 170675635Siedowse if (debug) 170775635Siedowse fprintf(stderr, 170875635Siedowse "ignoring duplicate host %s\n", 170975635Siedowse ai->ai_canonname); 171075635Siedowse grp->gr_type = GT_IGNORE; 171175635Siedowse return (0); 171275635Siedowse } 171375635Siedowse } 171474462Salfred ai = ai->ai_next; 17151558Srgrimes } 171675635Siedowse grp->gr_type = GT_HOST; 17171558Srgrimes return (0); 17181558Srgrimes} 17191558Srgrimes 17201558Srgrimes/* 17211558Srgrimes * Free up an exports list component 17221558Srgrimes */ 17231558Srgrimesvoid 17241558Srgrimesfree_exp(ep) 17251558Srgrimes struct exportlist *ep; 17261558Srgrimes{ 17271558Srgrimes 17281558Srgrimes if (ep->ex_defdir) { 17291558Srgrimes free_host(ep->ex_defdir->dp_hosts); 17301558Srgrimes free((caddr_t)ep->ex_defdir); 17311558Srgrimes } 17321558Srgrimes if (ep->ex_fsdir) 17331558Srgrimes free(ep->ex_fsdir); 173427447Sdfr if (ep->ex_indexfile) 173527447Sdfr free(ep->ex_indexfile); 17361558Srgrimes free_dir(ep->ex_dirl); 17371558Srgrimes free((caddr_t)ep); 17381558Srgrimes} 17391558Srgrimes 17401558Srgrimes/* 17411558Srgrimes * Free hosts. 17421558Srgrimes */ 17431558Srgrimesvoid 17441558Srgrimesfree_host(hp) 17451558Srgrimes struct hostlist *hp; 17461558Srgrimes{ 17471558Srgrimes struct hostlist *hp2; 17481558Srgrimes 17491558Srgrimes while (hp) { 17501558Srgrimes hp2 = hp; 17511558Srgrimes hp = hp->ht_next; 17521558Srgrimes free((caddr_t)hp2); 17531558Srgrimes } 17541558Srgrimes} 17551558Srgrimes 17561558Srgrimesstruct hostlist * 17571558Srgrimesget_ht() 17581558Srgrimes{ 17591558Srgrimes struct hostlist *hp; 17601558Srgrimes 17611558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 17621558Srgrimes if (hp == (struct hostlist *)NULL) 17631558Srgrimes out_of_mem(); 17641558Srgrimes hp->ht_next = (struct hostlist *)NULL; 17659336Sdfr hp->ht_flag = 0; 17661558Srgrimes return (hp); 17671558Srgrimes} 17681558Srgrimes 17691558Srgrimes/* 17701558Srgrimes * Out of memory, fatal 17711558Srgrimes */ 17721558Srgrimesvoid 17731558Srgrimesout_of_mem() 17741558Srgrimes{ 17751558Srgrimes 177637663Scharnier syslog(LOG_ERR, "out of memory"); 17771558Srgrimes exit(2); 17781558Srgrimes} 17791558Srgrimes 17801558Srgrimes/* 17811558Srgrimes * Do the mount syscall with the update flag to push the export info into 17821558Srgrimes * the kernel. 17831558Srgrimes */ 17841558Srgrimesint 17851558Srgrimesdo_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 17861558Srgrimes struct exportlist *ep; 17871558Srgrimes struct grouplist *grp; 17881558Srgrimes int exflags; 178972650Sgreen struct xucred *anoncrp; 17901558Srgrimes char *dirp; 17911558Srgrimes int dirplen; 17921558Srgrimes struct statfs *fsb; 17931558Srgrimes{ 179475841Siedowse struct statfs fsb1; 179574462Salfred struct addrinfo *ai; 179675801Siedowse struct export_args *eap; 179774462Salfred char *cp = NULL; 17981558Srgrimes int done; 17991558Srgrimes char savedc = '\0'; 18001558Srgrimes union { 18011558Srgrimes struct ufs_args ua; 18021558Srgrimes struct iso_args ia; 18039336Sdfr struct msdosfs_args da; 180454093Ssemenu struct ntfs_args na; 18051558Srgrimes } args; 18061558Srgrimes 180775801Siedowse bzero(&args, sizeof args); 180875801Siedowse /* XXX, we assume that all xx_args look like ufs_args. */ 18091558Srgrimes args.ua.fspec = 0; 181075801Siedowse eap = &args.ua.export; 181175801Siedowse 181275801Siedowse eap->ex_flags = exflags; 181375801Siedowse eap->ex_anon = *anoncrp; 181475801Siedowse eap->ex_indexfile = ep->ex_indexfile; 181575641Siedowse if (grp->gr_type == GT_HOST) 181674462Salfred ai = grp->gr_ptr.gt_addrinfo; 181775641Siedowse else 181875641Siedowse ai = NULL; 18191558Srgrimes done = FALSE; 18201558Srgrimes while (!done) { 18211558Srgrimes switch (grp->gr_type) { 18221558Srgrimes case GT_HOST: 182375641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 182474462Salfred goto skip; 182575801Siedowse eap->ex_addr = ai->ai_addr; 182675801Siedowse eap->ex_addrlen = ai->ai_addrlen; 182775801Siedowse eap->ex_masklen = 0; 18281558Srgrimes break; 18291558Srgrimes case GT_NET: 183075801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 183174462Salfred have_v6 == 0) 183274462Salfred goto skip; 183375801Siedowse eap->ex_addr = 183475801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 183575801Siedowse eap->ex_addrlen = args.ua.export.ex_addr->sa_len; 183675801Siedowse eap->ex_mask = 183775801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 183875801Siedowse eap->ex_masklen = args.ua.export.ex_mask->sa_len; 18391558Srgrimes break; 184075641Siedowse case GT_DEFAULT: 184175801Siedowse eap->ex_addr = NULL; 184275801Siedowse eap->ex_addrlen = 0; 184375801Siedowse eap->ex_mask = NULL; 184475801Siedowse eap->ex_masklen = 0; 184575641Siedowse break; 18467401Swpaul case GT_IGNORE: 18477401Swpaul return(0); 18487401Swpaul break; 18491558Srgrimes default: 185037663Scharnier syslog(LOG_ERR, "bad grouptype"); 18511558Srgrimes if (cp) 18521558Srgrimes *cp = savedc; 18531558Srgrimes return (1); 18541558Srgrimes }; 18551558Srgrimes 18561558Srgrimes /* 18571558Srgrimes * XXX: 18581558Srgrimes * Maybe I should just use the fsb->f_mntonname path instead 18591558Srgrimes * of looping back up the dirp to the mount point?? 18601558Srgrimes * Also, needs to know how to export all types of local 186196707Strhodes * exportable filesystems and not just "ufs". 18621558Srgrimes */ 18639336Sdfr while (mount(fsb->f_fstypename, dirp, 186474462Salfred fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 18651558Srgrimes if (cp) 18661558Srgrimes *cp-- = savedc; 18671558Srgrimes else 18681558Srgrimes cp = dirp + dirplen - 1; 1869100336Sjoerg if (opt_flags & OP_QUIET) 1870100336Sjoerg return (1); 18711558Srgrimes if (errno == EPERM) { 187275635Siedowse if (debug) 187375635Siedowse warnx("can't change attributes for %s", 187475635Siedowse dirp); 18751558Srgrimes syslog(LOG_ERR, 187637663Scharnier "can't change attributes for %s", dirp); 18771558Srgrimes return (1); 18781558Srgrimes } 18791558Srgrimes if (opt_flags & OP_ALLDIRS) { 1880100336Sjoerg if (errno == EINVAL) 1881100336Sjoerg syslog(LOG_ERR, 1882100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 1883100336Sjoerg dirp); 1884100336Sjoerg else 1885100336Sjoerg syslog(LOG_ERR, 1886100336Sjoerg "could not remount %s: %m", 1887100336Sjoerg dirp); 18881558Srgrimes return (1); 18891558Srgrimes } 18901558Srgrimes /* back up over the last component */ 18911558Srgrimes while (*cp == '/' && cp > dirp) 18921558Srgrimes cp--; 18931558Srgrimes while (*(cp - 1) != '/' && cp > dirp) 18941558Srgrimes cp--; 18951558Srgrimes if (cp == dirp) { 18961558Srgrimes if (debug) 189737663Scharnier warnx("mnt unsucc"); 189837663Scharnier syslog(LOG_ERR, "can't export %s", dirp); 18991558Srgrimes return (1); 19001558Srgrimes } 19011558Srgrimes savedc = *cp; 19021558Srgrimes *cp = '\0'; 190375841Siedowse /* Check that we're still on the same filesystem. */ 190475841Siedowse if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid, 190575841Siedowse &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) { 190675841Siedowse *cp = savedc; 190775841Siedowse syslog(LOG_ERR, "can't export %s", dirp); 190875841Siedowse return (1); 190975841Siedowse } 19101558Srgrimes } 191174462Salfredskip: 191275641Siedowse if (ai != NULL) 191374462Salfred ai = ai->ai_next; 191475641Siedowse if (ai == NULL) 19151558Srgrimes done = TRUE; 19161558Srgrimes } 19171558Srgrimes if (cp) 19181558Srgrimes *cp = savedc; 19191558Srgrimes return (0); 19201558Srgrimes} 19211558Srgrimes 19221558Srgrimes/* 19231558Srgrimes * Translate a net address. 192475801Siedowse * 192575801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 19261558Srgrimes */ 19271558Srgrimesint 19281558Srgrimesget_net(cp, net, maskflg) 19291558Srgrimes char *cp; 19301558Srgrimes struct netmsk *net; 19311558Srgrimes int maskflg; 19321558Srgrimes{ 193375861Siedowse struct netent *np = NULL; 193474462Salfred char *name, *p, *prefp; 193575801Siedowse struct sockaddr_in sin; 193675861Siedowse struct sockaddr *sa = NULL; 193774462Salfred struct addrinfo hints, *ai = NULL; 193874462Salfred char netname[NI_MAXHOST]; 193974462Salfred long preflen; 19401558Srgrimes 194175635Siedowse p = prefp = NULL; 194274462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 194374462Salfred p = strchr(cp, '/'); 194474462Salfred *p = '\0'; 194574462Salfred prefp = p + 1; 194674462Salfred } 194774462Salfred 194875861Siedowse /* 194975861Siedowse * Check for a numeric address first. We wish to avoid 195075861Siedowse * possible DNS lookups in getnetbyname(). 195175861Siedowse */ 195275861Siedowse if (isxdigit(*cp) || *cp == ':') { 195374462Salfred memset(&hints, 0, sizeof hints); 195475801Siedowse /* Ensure the mask and the network have the same family. */ 195575801Siedowse if (maskflg && (opt_flags & OP_NET)) 195675801Siedowse hints.ai_family = net->nt_net.ss_family; 195775801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 195875801Siedowse hints.ai_family = net->nt_mask.ss_family; 195975801Siedowse else 196075801Siedowse hints.ai_family = AF_UNSPEC; 196174462Salfred hints.ai_flags = AI_NUMERICHOST; 196275861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 196375861Siedowse sa = ai->ai_addr; 196475861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 196574462Salfred /* 196675801Siedowse * The address in `cp' is really a network address, so 196775801Siedowse * use inet_network() to re-interpret this correctly. 196875801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 196974462Salfred */ 197075801Siedowse bzero(&sin, sizeof sin); 197174462Salfred sin.sin_family = AF_INET; 197274462Salfred sin.sin_len = sizeof sin; 197375801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 197474462Salfred if (debug) 197575801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 197675801Siedowse inet_ntoa(sin.sin_addr)); 197774462Salfred sa = (struct sockaddr *)&sin; 197875861Siedowse } 197975861Siedowse } 198075861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 198175861Siedowse bzero(&sin, sizeof sin); 198275861Siedowse sin.sin_family = AF_INET; 198375861Siedowse sin.sin_len = sizeof sin; 198475861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 198575861Siedowse sa = (struct sockaddr *)&sin; 198675861Siedowse } 198775861Siedowse if (sa == NULL) 198874462Salfred goto fail; 198925318Spst 199075801Siedowse if (maskflg) { 199175801Siedowse /* The specified sockaddr is a mask. */ 199275801Siedowse if (checkmask(sa) != 0) 199375801Siedowse goto fail; 199475801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 199575801Siedowse opt_flags |= OP_HAVEMASK; 199675801Siedowse } else { 199775801Siedowse /* The specified sockaddr is a network address. */ 199875801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 199974462Salfred 200075801Siedowse /* Get a network name for the export list. */ 200175801Siedowse if (np) { 200275801Siedowse name = np->n_name; 200375801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2004146187Sume NULL, 0, NI_NUMERICHOST) == 0) { 200575801Siedowse name = netname; 200675801Siedowse } else { 200775801Siedowse goto fail; 200875801Siedowse } 200975801Siedowse if ((net->nt_name = strdup(name)) == NULL) 201075801Siedowse out_of_mem(); 201175801Siedowse 201275801Siedowse /* 201375801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 201475801Siedowse * from the class of an IPv4 address. 201575801Siedowse */ 201674462Salfred if (opt_flags & OP_MASKLEN) { 201774462Salfred preflen = strtol(prefp, NULL, 10); 201875801Siedowse if (preflen < 0L || preflen == LONG_MAX) 201974462Salfred goto fail; 202075801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 202175801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 202275801Siedowse goto fail; 202375801Siedowse opt_flags |= OP_HAVEMASK; 202474462Salfred *p = '/'; 202575801Siedowse } else if (sa->sa_family == AF_INET && 202675801Siedowse (opt_flags & OP_MASK) == 0) { 202775801Siedowse in_addr_t addr; 202874462Salfred 202975801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 203075801Siedowse if (IN_CLASSA(addr)) 203175801Siedowse preflen = 8; 203275801Siedowse else if (IN_CLASSB(addr)) 203375801Siedowse preflen = 16; 203475801Siedowse else if (IN_CLASSC(addr)) 203575801Siedowse preflen = 24; 203675801Siedowse else if (IN_CLASSD(addr)) 203775801Siedowse preflen = 28; 203875801Siedowse else 203975801Siedowse preflen = 32; /* XXX */ 204075801Siedowse 204175801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 204275801Siedowse makemask(&net->nt_mask, (int)preflen); 204375801Siedowse opt_flags |= OP_HAVEMASK; 204474462Salfred } 204574462Salfred } 204674462Salfred 204774462Salfred if (ai) 204874462Salfred freeaddrinfo(ai); 204974462Salfred return 0; 205074462Salfred 205174462Salfredfail: 205274462Salfred if (ai) 205374462Salfred freeaddrinfo(ai); 205474462Salfred return 1; 20551558Srgrimes} 20561558Srgrimes 20571558Srgrimes/* 20581558Srgrimes * Parse out the next white space separated field 20591558Srgrimes */ 20601558Srgrimesvoid 20611558Srgrimesnextfield(cp, endcp) 20621558Srgrimes char **cp; 20631558Srgrimes char **endcp; 20641558Srgrimes{ 20651558Srgrimes char *p; 20661558Srgrimes 20671558Srgrimes p = *cp; 20681558Srgrimes while (*p == ' ' || *p == '\t') 20691558Srgrimes p++; 20701558Srgrimes if (*p == '\n' || *p == '\0') 20711558Srgrimes *cp = *endcp = p; 20721558Srgrimes else { 20731558Srgrimes *cp = p++; 20741558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 20751558Srgrimes p++; 20761558Srgrimes *endcp = p; 20771558Srgrimes } 20781558Srgrimes} 20791558Srgrimes 20801558Srgrimes/* 20811558Srgrimes * Get an exports file line. Skip over blank lines and handle line 20821558Srgrimes * continuations. 20831558Srgrimes */ 20841558Srgrimesint 20851558Srgrimesget_line() 20861558Srgrimes{ 20871558Srgrimes char *p, *cp; 208896622Siedowse size_t len; 20891558Srgrimes int totlen, cont_line; 20901558Srgrimes 20911558Srgrimes /* 20921558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 20931558Srgrimes */ 20941558Srgrimes p = line; 20951558Srgrimes totlen = 0; 20961558Srgrimes do { 209796622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 20981558Srgrimes return (0); 20991558Srgrimes cp = p + len - 1; 21001558Srgrimes cont_line = 0; 21011558Srgrimes while (cp >= p && 21021558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 21031558Srgrimes if (*cp == '\\') 21041558Srgrimes cont_line = 1; 21051558Srgrimes cp--; 21061558Srgrimes len--; 21071558Srgrimes } 210879117Sdd if (cont_line) { 210979117Sdd *++cp = ' '; 211079117Sdd len++; 211179117Sdd } 211296622Siedowse if (linesize < len + totlen + 1) { 211396622Siedowse linesize = len + totlen + 1; 211496622Siedowse line = realloc(line, linesize); 211596622Siedowse if (line == NULL) 211696622Siedowse out_of_mem(); 21171558Srgrimes } 211896622Siedowse memcpy(line + totlen, p, len); 211996622Siedowse totlen += len; 212096622Siedowse line[totlen] = '\0'; 21211558Srgrimes } while (totlen == 0 || cont_line); 21221558Srgrimes return (1); 21231558Srgrimes} 21241558Srgrimes 21251558Srgrimes/* 21261558Srgrimes * Parse a description of a credential. 21271558Srgrimes */ 21281558Srgrimesvoid 21291558Srgrimesparsecred(namelist, cr) 21301558Srgrimes char *namelist; 213172650Sgreen struct xucred *cr; 21321558Srgrimes{ 21331558Srgrimes char *name; 21341558Srgrimes int cnt; 21351558Srgrimes char *names; 21361558Srgrimes struct passwd *pw; 21371558Srgrimes struct group *gr; 2138136051Sstefanf gid_t groups[NGROUPS + 1]; 2139136051Sstefanf int ngroups; 21401558Srgrimes 214191354Sdd cr->cr_version = XUCRED_VERSION; 21421558Srgrimes /* 214337663Scharnier * Set up the unprivileged user. 21441558Srgrimes */ 21451558Srgrimes cr->cr_uid = -2; 21461558Srgrimes cr->cr_groups[0] = -2; 21471558Srgrimes cr->cr_ngroups = 1; 21481558Srgrimes /* 21491558Srgrimes * Get the user's password table entry. 21501558Srgrimes */ 21511558Srgrimes names = strsep(&namelist, " \t\n"); 21521558Srgrimes name = strsep(&names, ":"); 21531558Srgrimes if (isdigit(*name) || *name == '-') 21541558Srgrimes pw = getpwuid(atoi(name)); 21551558Srgrimes else 21561558Srgrimes pw = getpwnam(name); 21571558Srgrimes /* 21581558Srgrimes * Credentials specified as those of a user. 21591558Srgrimes */ 21601558Srgrimes if (names == NULL) { 21611558Srgrimes if (pw == NULL) { 216237663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 21631558Srgrimes return; 21641558Srgrimes } 21651558Srgrimes cr->cr_uid = pw->pw_uid; 21661558Srgrimes ngroups = NGROUPS + 1; 21671558Srgrimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 216837663Scharnier syslog(LOG_ERR, "too many groups"); 21691558Srgrimes /* 2170136051Sstefanf * Compress out duplicate. 21711558Srgrimes */ 21721558Srgrimes cr->cr_ngroups = ngroups - 1; 21731558Srgrimes cr->cr_groups[0] = groups[0]; 21741558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 21751558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 21761558Srgrimes return; 21771558Srgrimes } 21781558Srgrimes /* 21791558Srgrimes * Explicit credential specified as a colon separated list: 21801558Srgrimes * uid:gid:gid:... 21811558Srgrimes */ 21821558Srgrimes if (pw != NULL) 21831558Srgrimes cr->cr_uid = pw->pw_uid; 21841558Srgrimes else if (isdigit(*name) || *name == '-') 21851558Srgrimes cr->cr_uid = atoi(name); 21861558Srgrimes else { 218737663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 21881558Srgrimes return; 21891558Srgrimes } 21901558Srgrimes cr->cr_ngroups = 0; 21911558Srgrimes while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 21921558Srgrimes name = strsep(&names, ":"); 21931558Srgrimes if (isdigit(*name) || *name == '-') { 21941558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 21951558Srgrimes } else { 21961558Srgrimes if ((gr = getgrnam(name)) == NULL) { 219737663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 21981558Srgrimes continue; 21991558Srgrimes } 22001558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 22011558Srgrimes } 22021558Srgrimes } 22031558Srgrimes if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 220437663Scharnier syslog(LOG_ERR, "too many groups"); 22051558Srgrimes} 22061558Srgrimes 22071558Srgrimes#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 22081558Srgrimes/* 22091558Srgrimes * Routines that maintain the remote mounttab 22101558Srgrimes */ 22111558Srgrimesvoid 22121558Srgrimesget_mountlist() 22131558Srgrimes{ 22141558Srgrimes struct mountlist *mlp, **mlpp; 221523681Speter char *host, *dirp, *cp; 22161558Srgrimes char str[STRSIZ]; 22171558Srgrimes FILE *mlfile; 22181558Srgrimes 22191558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 222053117Sbillf if (errno == ENOENT) 222153117Sbillf return; 222253117Sbillf else { 222353117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 222453117Sbillf return; 222553117Sbillf } 22261558Srgrimes } 22271558Srgrimes mlpp = &mlhead; 22281558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 222923681Speter cp = str; 223023681Speter host = strsep(&cp, " \t\n"); 223123681Speter dirp = strsep(&cp, " \t\n"); 223223681Speter if (host == NULL || dirp == NULL) 22331558Srgrimes continue; 22341558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 223537663Scharnier if (mlp == (struct mountlist *)NULL) 223637663Scharnier out_of_mem(); 223723681Speter strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 223823681Speter mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 223923681Speter strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 224023681Speter mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 22411558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 22421558Srgrimes *mlpp = mlp; 22431558Srgrimes mlpp = &mlp->ml_next; 22441558Srgrimes } 22451558Srgrimes fclose(mlfile); 22461558Srgrimes} 22471558Srgrimes 224875635Siedowsevoid 224975635Siedowsedel_mlist(char *hostp, char *dirp) 22501558Srgrimes{ 22511558Srgrimes struct mountlist *mlp, **mlpp; 22521558Srgrimes struct mountlist *mlp2; 22531558Srgrimes FILE *mlfile; 22541558Srgrimes int fnd = 0; 22551558Srgrimes 22561558Srgrimes mlpp = &mlhead; 22571558Srgrimes mlp = mlhead; 22581558Srgrimes while (mlp) { 22591558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 22601558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 22611558Srgrimes fnd = 1; 22621558Srgrimes mlp2 = mlp; 22631558Srgrimes *mlpp = mlp = mlp->ml_next; 22641558Srgrimes free((caddr_t)mlp2); 22651558Srgrimes } else { 22661558Srgrimes mlpp = &mlp->ml_next; 22671558Srgrimes mlp = mlp->ml_next; 22681558Srgrimes } 22691558Srgrimes } 22701558Srgrimes if (fnd) { 22711558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 227237663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 22731558Srgrimes return; 22741558Srgrimes } 22751558Srgrimes mlp = mlhead; 22761558Srgrimes while (mlp) { 22771558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 22781558Srgrimes mlp = mlp->ml_next; 22791558Srgrimes } 22801558Srgrimes fclose(mlfile); 22811558Srgrimes } 22821558Srgrimes} 22831558Srgrimes 22841558Srgrimesvoid 22851558Srgrimesadd_mlist(hostp, dirp) 22861558Srgrimes char *hostp, *dirp; 22871558Srgrimes{ 22881558Srgrimes struct mountlist *mlp, **mlpp; 22891558Srgrimes FILE *mlfile; 22901558Srgrimes 22911558Srgrimes mlpp = &mlhead; 22921558Srgrimes mlp = mlhead; 22931558Srgrimes while (mlp) { 22941558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 22951558Srgrimes return; 22961558Srgrimes mlpp = &mlp->ml_next; 22971558Srgrimes mlp = mlp->ml_next; 22981558Srgrimes } 22991558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 230037663Scharnier if (mlp == (struct mountlist *)NULL) 230137663Scharnier out_of_mem(); 23021558Srgrimes strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 23031558Srgrimes mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 23041558Srgrimes strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 23051558Srgrimes mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 23061558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 23071558Srgrimes *mlpp = mlp; 23081558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 230937663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 23101558Srgrimes return; 23111558Srgrimes } 23121558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 23131558Srgrimes fclose(mlfile); 23141558Srgrimes} 23151558Srgrimes 23161558Srgrimes/* 23171558Srgrimes * Free up a group list. 23181558Srgrimes */ 23191558Srgrimesvoid 23201558Srgrimesfree_grp(grp) 23211558Srgrimes struct grouplist *grp; 23221558Srgrimes{ 23231558Srgrimes if (grp->gr_type == GT_HOST) { 232474462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 232574462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 23261558Srgrimes } else if (grp->gr_type == GT_NET) { 23271558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 23281558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 23291558Srgrimes } 23301558Srgrimes free((caddr_t)grp); 23311558Srgrimes} 23321558Srgrimes 23331558Srgrimes#ifdef DEBUG 23341558Srgrimesvoid 23351558SrgrimesSYSLOG(int pri, const char *fmt, ...) 23361558Srgrimes{ 23371558Srgrimes va_list ap; 23381558Srgrimes 23391558Srgrimes va_start(ap, fmt); 23401558Srgrimes vfprintf(stderr, fmt, ap); 23411558Srgrimes va_end(ap); 23421558Srgrimes} 23431558Srgrimes#endif /* DEBUG */ 23441558Srgrimes 23451558Srgrimes/* 23461558Srgrimes * Check options for consistency. 23471558Srgrimes */ 23481558Srgrimesint 23491558Srgrimescheck_options(dp) 23501558Srgrimes struct dirlist *dp; 23511558Srgrimes{ 23521558Srgrimes 23531558Srgrimes if (dp == (struct dirlist *)NULL) 23541558Srgrimes return (1); 235583653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 235683653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 23571558Srgrimes return (1); 23581558Srgrimes } 23591558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 236075801Siedowse syslog(LOG_ERR, "-mask requires -network"); 236175801Siedowse return (1); 23621558Srgrimes } 236375801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 236475801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 236575801Siedowse return (1); 236675801Siedowse } 236775801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 236875801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 236975801Siedowse return (1); 237075801Siedowse } 23711558Srgrimes if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 237245927Salex syslog(LOG_ERR, "-alldirs has multiple directories"); 23731558Srgrimes return (1); 23741558Srgrimes } 23751558Srgrimes return (0); 23761558Srgrimes} 23771558Srgrimes 23781558Srgrimes/* 23791558Srgrimes * Check an absolute directory path for any symbolic links. Return true 23801558Srgrimes */ 23811558Srgrimesint 23821558Srgrimescheck_dirpath(dirp) 23831558Srgrimes char *dirp; 23841558Srgrimes{ 23851558Srgrimes char *cp; 23861558Srgrimes int ret = 1; 23871558Srgrimes struct stat sb; 23881558Srgrimes 23891558Srgrimes cp = dirp + 1; 23901558Srgrimes while (*cp && ret) { 23911558Srgrimes if (*cp == '/') { 23921558Srgrimes *cp = '\0'; 23939336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 23941558Srgrimes ret = 0; 23951558Srgrimes *cp = '/'; 23961558Srgrimes } 23971558Srgrimes cp++; 23981558Srgrimes } 23999336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 24001558Srgrimes ret = 0; 24011558Srgrimes return (ret); 24021558Srgrimes} 24039336Sdfr 240475801Siedowse/* 240575801Siedowse * Make a netmask according to the specified prefix length. The ss_family 240675801Siedowse * and other non-address fields must be initialised before calling this. 240775801Siedowse */ 240875801Siedowseint 240975801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 241074462Salfred{ 241175801Siedowse u_char *p; 241275801Siedowse int bits, i, len; 241374462Salfred 241475801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 241575801Siedowse return (-1); 2416103949Smike if (bitlen > len * CHAR_BIT) 241775801Siedowse return (-1); 241874462Salfred 241975801Siedowse for (i = 0; i < len; i++) { 2420103949Smike bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 242175801Siedowse *p++ = (1 << bits) - 1; 242275801Siedowse bitlen -= bits; 242374462Salfred } 242475801Siedowse return 0; 242574462Salfred} 242674462Salfred 242775801Siedowse/* 242875801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 242975801Siedowse * is acceptable (i.e. of the form 1...10....0). 243075801Siedowse */ 243175801Siedowseint 243275801Siedowsecheckmask(struct sockaddr *sa) 243374462Salfred{ 243475801Siedowse u_char *mask; 243575801Siedowse int i, len; 243674462Salfred 243775801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 243875801Siedowse return (-1); 243975801Siedowse 244075801Siedowse for (i = 0; i < len; i++) 244175801Siedowse if (mask[i] != 0xff) 244275801Siedowse break; 244375801Siedowse if (i < len) { 244475801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 244575801Siedowse return (-1); 244675801Siedowse i++; 244774462Salfred } 244875801Siedowse for (; i < len; i++) 244975801Siedowse if (mask[i] != 0) 245075801Siedowse return (-1); 245175801Siedowse return (0); 245274462Salfred} 245374462Salfred 245475801Siedowse/* 245575801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 245675801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 245775801Siedowse * If samask is NULL, perform a full comparision. 245875801Siedowse */ 245975801Siedowseint 246075801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 246174462Salfred{ 246275801Siedowse unsigned char *p1, *p2, *mask; 246375801Siedowse int len, i; 246474462Salfred 246575801Siedowse if (sa1->sa_family != sa2->sa_family || 246675801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 246775801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 246875801Siedowse return (1); 246975801Siedowse 247075801Siedowse switch (sa1->sa_family) { 247174462Salfred case AF_INET6: 247275801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 247375801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 247475801Siedowse return (1); 247574462Salfred break; 247674462Salfred } 247774462Salfred 247875801Siedowse /* Simple binary comparison if no mask specified. */ 247975801Siedowse if (samask == NULL) 248075801Siedowse return (memcmp(p1, p2, len)); 248174462Salfred 248275801Siedowse /* Set up the mask, and do a mask-based comparison. */ 248375801Siedowse if (sa1->sa_family != samask->sa_family || 248475801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 248575801Siedowse return (1); 248674462Salfred 248775801Siedowse for (i = 0; i < len; i++) 248875801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 248975801Siedowse return (1); 249075801Siedowse return (0); 249174462Salfred} 249274462Salfred 249375801Siedowse/* 249475801Siedowse * Return a pointer to the part of the sockaddr that contains the 249575801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 249675801Siedowse * NULL if the address family is unknown. 249775801Siedowse */ 249875801Siedowsevoid * 249975801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 250075801Siedowse void *p; 250174462Salfred int len; 250274462Salfred 250375801Siedowse switch (sa->sa_family) { 250474462Salfred case AF_INET: 250575801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 250675801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 250774462Salfred break; 250874462Salfred case AF_INET6: 250975801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 251075801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 251174462Salfred break; 251274462Salfred default: 251375801Siedowse p = NULL; 251475801Siedowse len = 0; 251574462Salfred } 251674462Salfred 251775801Siedowse if (nbytes != NULL) 251875801Siedowse *nbytes = len; 251975801Siedowse return (p); 252074462Salfred} 252174462Salfred 252275754Siedowsevoid 252375754Siedowsehuphandler(int sig) 252475754Siedowse{ 252575754Siedowse got_sighup = 1; 252675754Siedowse} 252775754Siedowse 252874462Salfredvoid terminate(sig) 252974462Salfredint sig; 253074462Salfred{ 2531149433Spjd pidfile_remove(pfh); 253274792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 253374792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 253474462Salfred exit (0); 253574462Salfred} 2536