mountd.c revision 8871
1161764Sobrien/* 279968Sobrien * Copyright (c) 1989, 1993 379968Sobrien * The Regents of the University of California. All rights reserved. 4133936Sobrien * 579968Sobrien * This code is derived from software contributed to Berkeley by 679968Sobrien * Herb Hasler and Rick Macklem at The University of Guelph. 779968Sobrien * 879968Sobrien * Redistribution and use in source and binary forms, with or without 979968Sobrien * modification, are permitted provided that the following conditions 1079968Sobrien * are met: 1179968Sobrien * 1. Redistributions of source code must retain the above copyright 1279968Sobrien * notice, this list of conditions and the following disclaimer. 1379968Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1479968Sobrien * notice, this list of conditions and the following disclaimer in the 1579968Sobrien * documentation and/or other materials provided with the distribution. 1679968Sobrien * 3. All advertising materials mentioning features or use of this software 1779968Sobrien * must display the following acknowledgement: 1879968Sobrien * This product includes software developed by the University of 1979968Sobrien * California, Berkeley and its contributors. 2079968Sobrien * 4. Neither the name of the University nor the names of its contributors 2179968Sobrien * may be used to endorse or promote products derived from this software 2279968Sobrien * without specific prior written permission. 2379968Sobrien * 2479968Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2579968Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2679968Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2779968Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2879968Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2979968Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3079968Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3179968Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3279968Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3379968Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3479968Sobrien * SUCH DAMAGE. 3579968Sobrien */ 3679968Sobrien 3779968Sobrien#ifndef lint 3879968Sobrienstatic char copyright[] = 3979968Sobrien"@(#) Copyright (c) 1989, 1993\n\ 4079968Sobrien The Regents of the University of California. All rights reserved.\n"; 4179968Sobrien#endif /*not lint*/ 4279968Sobrien 4379968Sobrien#ifndef lint 4479968Sobrien/*static char sccsid[] = "From: @(#)mountd.c 8.8 (Berkeley) 2/20/94";*/ 4579968Sobrienstatic const char rcsid[] = 4679968Sobrien "$Id: mountd.c,v 1.6 1995/05/21 19:31:09 phk Exp $"; 4779968Sobrien#endif /*not lint*/ 4879968Sobrien 4979968Sobrien#include <sys/param.h> 5079968Sobrien#include <sys/file.h> 51133936Sobrien#include <sys/ioctl.h> 5279968Sobrien#include <sys/mount.h> 5379968Sobrien#include <sys/socket.h> 5479968Sobrien#include <sys/stat.h> 5579968Sobrien#include <sys/syslog.h> 5679968Sobrien#include <sys/ucred.h> 5779968Sobrien 5879968Sobrien#include <rpc/rpc.h> 5979968Sobrien#include <rpc/pmap_clnt.h> 6079968Sobrien#include <rpc/pmap_prot.h> 6179968Sobrien#ifdef ISO 6279968Sobrien#include <netiso/iso.h> 6379968Sobrien#endif 6479968Sobrien#include <nfs/rpcv2.h> 6579968Sobrien#include <nfs/nfsv2.h> 6679968Sobrien 6779968Sobrien#include <arpa/inet.h> 6879968Sobrien 6979968Sobrien#include <ctype.h> 7079968Sobrien#include <errno.h> 7179968Sobrien#include <grp.h> 7279968Sobrien#include <netdb.h> 7379968Sobrien#include <pwd.h> 7479968Sobrien#include <signal.h> 7579968Sobrien#include <stdio.h> 7679968Sobrien#include <stdlib.h> 7779968Sobrien#include <string.h> 7879968Sobrien#include <unistd.h> 7979968Sobrien#include "pathnames.h" 8079968Sobrien 8179968Sobrien#ifdef DEBUG 8279968Sobrien#include <stdarg.h> 8379968Sobrien#endif 8479968Sobrien 8579968Sobrien/* 8679968Sobrien * Structures for keeping the mount list and export list 8779968Sobrien */ 8879968Sobrienstruct mountlist { 8979968Sobrien struct mountlist *ml_next; 9079968Sobrien char ml_host[RPCMNT_NAMELEN+1]; 9179968Sobrien char ml_dirp[RPCMNT_PATHLEN+1]; 9279968Sobrien}; 9379968Sobrien 9479968Sobrienstruct dirlist { 9579968Sobrien struct dirlist *dp_left; 9679968Sobrien struct dirlist *dp_right; 9779968Sobrien int dp_flag; 98108746Sobrien struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 99108746Sobrien char dp_dirp[1]; /* Actually malloc'd to size of dir */ 100161764Sobrien}; 101108746Sobrien/* dp_flag bits */ 102108746Sobrien#define DP_DEFSET 0x1 103108746Sobrien 104108746Sobrienstruct exportlist { 105108746Sobrien struct exportlist *ex_next; 106108746Sobrien struct dirlist *ex_dirl; 107108746Sobrien struct dirlist *ex_defdir; 108108746Sobrien int ex_flag; 109108746Sobrien fsid_t ex_fs; 110108746Sobrien char *ex_fsdir; 111108746Sobrien}; 112108746Sobrien/* ex_flag bits */ 113108746Sobrien#define EX_LINKED 0x1 114108746Sobrien 115108746Sobrienstruct netmsk { 116108746Sobrien u_long nt_net; 117108746Sobrien u_long nt_mask; 118108746Sobrien char *nt_name; 119108746Sobrien}; 120108746Sobrien 12179968Sobrienunion grouptypes { 12279968Sobrien struct hostent *gt_hostent; 12392282Sobrien struct netmsk gt_net; 12492282Sobrien#ifdef ISO 12592282Sobrien struct sockaddr_iso *gt_isoaddr; 12692282Sobrien#endif 12792282Sobrien}; 12879968Sobrien 12979968Sobrienstruct grouplist { 13079968Sobrien int gr_type; 13179968Sobrien union grouptypes gr_ptr; 13279968Sobrien struct grouplist *gr_next; 13392282Sobrien}; 13479968Sobrien/* Group types */ 13579968Sobrien#define GT_NULL 0x0 13679968Sobrien#define GT_HOST 0x1 13779968Sobrien#define GT_NET 0x2 13879968Sobrien#define GT_ISO 0x4 13979968Sobrien#define GT_IGNORE 0x5 14079968Sobrien 14179968Sobrienstruct hostlist { 14279968Sobrien struct grouplist *ht_grp; 14379968Sobrien struct hostlist *ht_next; 14479968Sobrien}; 14579968Sobrien 14679968Sobrien/* Global defs */ 14779968Sobrienchar *add_expdir __P((struct dirlist **, char *, int)); 14879968Sobrienvoid add_dlist __P((struct dirlist **, struct dirlist *, 14979968Sobrien struct grouplist *)); 15079968Sobrienvoid add_mlist __P((char *, char *)); 15179968Sobrienint check_dirpath __P((char *)); 15279968Sobrienint check_options __P((struct dirlist *)); 15379968Sobrienint chk_host __P((struct dirlist *, u_long, int *)); 15479968Sobrienvoid del_mlist __P((char *, char *)); 15579968Sobrienstruct dirlist *dirp_search __P((struct dirlist *, char *)); 15679968Sobrienint do_mount __P((struct exportlist *, struct grouplist *, int, 15779968Sobrien struct ucred *, char *, int, struct statfs *)); 15879968Sobrienint do_opt __P((char **, char **, struct exportlist *, struct grouplist *, 15979968Sobrien int *, int *, struct ucred *)); 16079968Sobrienstruct exportlist *ex_search __P((fsid_t *)); 16179968Sobrienstruct exportlist *get_exp __P((void)); 16279968Sobrienvoid free_dir __P((struct dirlist *)); 16379968Sobrienvoid free_exp __P((struct exportlist *)); 16479968Sobrienvoid free_grp __P((struct grouplist *)); 16579968Sobrienvoid free_host __P((struct hostlist *)); 16679968Sobrienvoid get_exportlist __P((void)); 16779968Sobrienint get_host __P((char *, struct grouplist *, struct grouplist *)); 16879968Sobrienstruct hostlist *get_ht __P((void)); 169110242Sobrienint get_line __P((void)); 170110242Sobrienvoid get_mountlist __P((void)); 17179968Sobrienint get_net __P((char *, struct netmsk *, int)); 17279968Sobrienvoid getexp_err __P((struct exportlist *, struct grouplist *)); 17379968Sobrienstruct grouplist *get_grp __P((void)); 17479968Sobrienvoid hang_dirp __P((struct dirlist *, struct grouplist *, 17579968Sobrien struct exportlist *, int)); 17679968Sobrienvoid mntsrv __P((struct svc_req *, SVCXPRT *)); 17779968Sobrienvoid nextfield __P((char **, char **)); 17879968Sobrienvoid out_of_mem __P((void)); 17979968Sobrienvoid parsecred __P((char *, struct ucred *)); 18079968Sobrienint put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *)); 181110242Sobrienint scan_tree __P((struct dirlist *, u_long)); 182110242Sobrienvoid send_umntall __P((void)); 183110242Sobrienint umntall_each __P((caddr_t, struct sockaddr_in *)); 18479968Sobrienint xdr_dir __P((XDR *, char *)); 18579968Sobrienint xdr_explist __P((XDR *, caddr_t)); 18679968Sobrienint xdr_fhs __P((XDR *, nfsv2fh_t *)); 18779968Sobrienint xdr_mlist __P((XDR *, caddr_t)); 18879968Sobrien 18979968Sobrien/* C library */ 19079968Sobrienint getnetgrent(); 19179968Sobrienvoid endnetgrent(); 19279968Sobrienvoid setnetgrent(); 19379968Sobrien 19479968Sobrien#ifdef ISO 19579968Sobrienstruct iso_addr *iso_addr(); 19679968Sobrien#endif 19779968Sobrien 19879968Sobrienstruct exportlist *exphead; 19979968Sobrienstruct mountlist *mlhead; 20079968Sobrienstruct grouplist *grphead; 20179968Sobrienchar exname[MAXPATHLEN]; 20279968Sobrienstruct ucred def_anon = { 20379968Sobrien 1, 20479968Sobrien (uid_t) -2, 20579968Sobrien 1, 20679968Sobrien { (gid_t) -2 } 20779968Sobrien}; 20879968Sobrienint root_only = 1; 20979968Sobrienint opt_flags; 21079968Sobrien/* Bits for above */ 21179968Sobrien#define OP_MAPROOT 0x01 21279968Sobrien#define OP_MAPALL 0x02 21379968Sobrien#define OP_KERB 0x04 21479968Sobrien#define OP_MASK 0x08 21579968Sobrien#define OP_NET 0x10 21679968Sobrien#define OP_ISO 0x20 21779968Sobrien#define OP_ALLDIRS 0x40 21879968Sobrien 21979968Sobrien#ifdef DEBUG 22079968Sobrienint debug = 1; 22179968Sobrienvoid SYSLOG __P((int, const char *, ...)); 22279968Sobrien#define syslog SYSLOG 22379968Sobrien#else 22479968Sobrienint debug = 0; 22579968Sobrien#endif 22679968Sobrien 22779968Sobrien/* 22879968Sobrien * Mountd server for NFS mount protocol as described in: 22979968Sobrien * NFS: Network File System Protocol Specification, RFC1094, Appendix A 23079968Sobrien * The optional arguments are the exports file name 23179968Sobrien * default: _PATH_EXPORTS 23279968Sobrien * and "-n" to allow nonroot mount. 23379968Sobrien */ 23479968Sobrienint 23579968Sobrienmain(argc, argv) 23679968Sobrien int argc; 23779968Sobrien char **argv; 23879968Sobrien{ 23979968Sobrien SVCXPRT *transp; 24079968Sobrien int c; 24179968Sobrien struct vfsconf *vfc; 24279968Sobrien 24379968Sobrien vfc = getvfsbyname("nfs"); 24479968Sobrien if(!vfc && vfsisloadable("nfs")) { 24579968Sobrien if(vfsload("nfs")) 24679968Sobrien err(1, "vfsload(nfs)"); 24779968Sobrien endvfsent(); /* flush cache */ 24879968Sobrien vfc = getvfsbyname("nfs"); 24979968Sobrien } 25079968Sobrien if(!vfc) { 25179968Sobrien errx(1, "NFS support is not available in the running kernel"); 25279968Sobrien } 25379968Sobrien 25479968Sobrien while ((c = getopt(argc, argv, "dn")) != EOF) 25592282Sobrien switch (c) { 25692282Sobrien case 'd': 25792282Sobrien debug = debug ? 0 : 1; 25879968Sobrien break; 25979968Sobrien case 'n': 26079968Sobrien root_only = 0; 26179968Sobrien break; 26292282Sobrien default: 26379968Sobrien fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); 26492282Sobrien exit(1); 26579968Sobrien }; 26679968Sobrien argc -= optind; 26779968Sobrien argv += optind; 26879968Sobrien grphead = (struct grouplist *)NULL; 26979968Sobrien exphead = (struct exportlist *)NULL; 27079968Sobrien mlhead = (struct mountlist *)NULL; 27179968Sobrien if (argc == 1) { 27292282Sobrien strncpy(exname, *argv, MAXPATHLEN-1); 27379968Sobrien exname[MAXPATHLEN-1] = '\0'; 27479968Sobrien } else 27579968Sobrien strcpy(exname, _PATH_EXPORTS); 27679968Sobrien openlog("mountd", LOG_PID, LOG_DAEMON); 27779968Sobrien if (debug) 27879968Sobrien fprintf(stderr,"Getting export list.\n"); 27979968Sobrien get_exportlist(); 28079968Sobrien if (debug) 28192282Sobrien fprintf(stderr,"Getting mount list.\n"); 28279968Sobrien get_mountlist(); 28379968Sobrien if (debug) 28479968Sobrien fprintf(stderr,"Here we go.\n"); 28579968Sobrien if (debug == 0) { 28679968Sobrien daemon(0, 0); 28779968Sobrien signal(SIGINT, SIG_IGN); 28879968Sobrien signal(SIGQUIT, SIG_IGN); 28979968Sobrien } 29079968Sobrien signal(SIGHUP, (void (*) __P((int))) get_exportlist); 29179968Sobrien signal(SIGTERM, (void (*) __P((int))) send_umntall); 29279968Sobrien { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 29379968Sobrien if (pidfile != NULL) { 29479968Sobrien fprintf(pidfile, "%d\n", getpid()); 29579968Sobrien fclose(pidfile); 29679968Sobrien } 29779968Sobrien } 29879968Sobrien if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { 29979968Sobrien syslog(LOG_ERR, "Can't create socket"); 30079968Sobrien exit(1); 30179968Sobrien } 30279968Sobrien pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 30379968Sobrien if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 30479968Sobrien IPPROTO_UDP)) { 30579968Sobrien syslog(LOG_ERR, "Can't register mount"); 30679968Sobrien exit(1); 30779968Sobrien } 30879968Sobrien svc_run(); 30979968Sobrien syslog(LOG_ERR, "Mountd died"); 31079968Sobrien exit(1); 31179968Sobrien} 31292282Sobrien 31379968Sobrien/* 31479968Sobrien * The mount rpc service 31579968Sobrien */ 31679968Sobrienvoid 31779968Sobrienmntsrv(rqstp, transp) 31879968Sobrien struct svc_req *rqstp; 31979968Sobrien SVCXPRT *transp; 32079968Sobrien{ 32179968Sobrien struct exportlist *ep; 32279968Sobrien struct dirlist *dp; 32379968Sobrien nfsv2fh_t nfh; 32479968Sobrien struct authunix_parms *ucr; 32579968Sobrien struct stat stb; 32679968Sobrien struct statfs fsb; 32779968Sobrien struct hostent *hp; 32879968Sobrien u_long saddr; 32979968Sobrien char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; 33079968Sobrien int bad = ENOENT, omask, defset; 33179968Sobrien uid_t uid = -2; 33279968Sobrien 333108746Sobrien /* Get authorization */ 33479968Sobrien switch (rqstp->rq_cred.oa_flavor) { 33579968Sobrien case AUTH_UNIX: 33679968Sobrien ucr = (struct authunix_parms *)rqstp->rq_clntcred; 337108746Sobrien uid = ucr->aup_uid; 33879968Sobrien break; 33979968Sobrien case AUTH_NULL: 34079968Sobrien default: 34179968Sobrien break; 34279968Sobrien } 34379968Sobrien 34479968Sobrien saddr = transp->xp_raddr.sin_addr.s_addr; 34579968Sobrien hp = (struct hostent *)NULL; 34679968Sobrien switch (rqstp->rq_proc) { 34779968Sobrien case NULLPROC: 34879968Sobrien if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 34979968Sobrien syslog(LOG_ERR, "Can't send reply"); 35079968Sobrien return; 35179968Sobrien case RPCMNT_MOUNT: 35279968Sobrien if ((uid != 0 && root_only) || uid == -2) { 35379968Sobrien svcerr_weakauth(transp); 35479968Sobrien return; 35579968Sobrien } 35679968Sobrien if (!svc_getargs(transp, xdr_dir, rpcpath)) { 35779968Sobrien svcerr_decode(transp); 35879968Sobrien return; 35979968Sobrien } 36079968Sobrien 36179968Sobrien /* 36279968Sobrien * Get the real pathname and make sure it is a directory 36379968Sobrien * that exists. 36479968Sobrien */ 36579968Sobrien if (realpath(rpcpath, dirpath) == 0 || 36679968Sobrien stat(dirpath, &stb) < 0 || 36779968Sobrien (stb.st_mode & S_IFMT) != S_IFDIR || 36879968Sobrien statfs(dirpath, &fsb) < 0) { 36979968Sobrien chdir("/"); /* Just in case realpath doesn't */ 37079968Sobrien if (debug) 37179968Sobrien fprintf(stderr, "stat failed on %s\n", dirpath); 37279968Sobrien if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 37379968Sobrien syslog(LOG_ERR, "Can't send reply"); 37479968Sobrien return; 37579968Sobrien } 37679968Sobrien 37779968Sobrien /* Check in the exports list */ 37879968Sobrien omask = sigblock(sigmask(SIGHUP)); 37979968Sobrien ep = ex_search(&fsb.f_fsid); 38079968Sobrien defset = 0; 38179968Sobrien if (ep && (chk_host(ep->ex_defdir, saddr, &defset) || 38279968Sobrien ((dp = dirp_search(ep->ex_dirl, dirpath)) && 38379968Sobrien chk_host(dp, saddr, &defset)) || 38479968Sobrien (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 38579968Sobrien scan_tree(ep->ex_dirl, saddr) == 0))) { 38679968Sobrien /* Get the file handle */ 38779968Sobrien bzero((caddr_t)&nfh, sizeof(nfh)); 38879968Sobrien if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { 38979968Sobrien bad = errno; 39079968Sobrien syslog(LOG_ERR, "Can't get fh for %s", dirpath); 39179968Sobrien if (!svc_sendreply(transp, xdr_long, 39279968Sobrien (caddr_t)&bad)) 39379968Sobrien syslog(LOG_ERR, "Can't send reply"); 394161764Sobrien sigsetmask(omask); 39579968Sobrien return; 39679968Sobrien } 39779968Sobrien if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) 39879968Sobrien syslog(LOG_ERR, "Can't send reply"); 39979968Sobrien if (hp == NULL) 40079968Sobrien hp = gethostbyaddr((caddr_t)&saddr, 40179968Sobrien sizeof(saddr), AF_INET); 40279968Sobrien if (hp) 40379968Sobrien add_mlist(hp->h_name, dirpath); 40479968Sobrien else 40579968Sobrien add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 40679968Sobrien dirpath); 407110242Sobrien if (debug) 408110242Sobrien fprintf(stderr,"Mount successfull.\n"); 409110242Sobrien } else { 410110242Sobrien bad = EACCES; 411110242Sobrien if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 412110242Sobrien syslog(LOG_ERR, "Can't send reply"); 413110242Sobrien } 414110242Sobrien sigsetmask(omask); 415110242Sobrien return; 41679968Sobrien case RPCMNT_DUMP: 41779968Sobrien if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) 41879968Sobrien syslog(LOG_ERR, "Can't send reply"); 41979968Sobrien return; 42079968Sobrien case RPCMNT_UMOUNT: 42179968Sobrien if ((uid != 0 && root_only) || uid == -2) { 42279968Sobrien svcerr_weakauth(transp); 42379968Sobrien return; 42479968Sobrien } 42579968Sobrien if (!svc_getargs(transp, xdr_dir, dirpath)) { 42679968Sobrien svcerr_decode(transp); 42779968Sobrien return; 42879968Sobrien } 42979968Sobrien if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 43079968Sobrien syslog(LOG_ERR, "Can't send reply"); 43179968Sobrien hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 43279968Sobrien if (hp) 43379968Sobrien del_mlist(hp->h_name, dirpath); 43479968Sobrien del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 43579968Sobrien return; 43679968Sobrien case RPCMNT_UMNTALL: 43779968Sobrien if ((uid != 0 && root_only) || uid == -2) { 43879968Sobrien svcerr_weakauth(transp); 43979968Sobrien return; 44079968Sobrien } 441161764Sobrien if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 44279968Sobrien syslog(LOG_ERR, "Can't send reply"); 44379968Sobrien hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 44479968Sobrien if (hp) 44579968Sobrien del_mlist(hp->h_name, (char *)NULL); 44679968Sobrien del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL); 44779968Sobrien return; 44879968Sobrien case RPCMNT_EXPORT: 44979968Sobrien if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) 45079968Sobrien syslog(LOG_ERR, "Can't send reply"); 45179968Sobrien return; 45279968Sobrien default: 45379968Sobrien svcerr_noproc(transp); 45479968Sobrien return; 45579968Sobrien } 45679968Sobrien} 45779968Sobrien 45879968Sobrien/* 45979968Sobrien * Xdr conversion for a dirpath string 46079968Sobrien */ 46179968Sobrienint 46279968Sobrienxdr_dir(xdrsp, dirp) 46379968Sobrien XDR *xdrsp; 46479968Sobrien char *dirp; 46579968Sobrien{ 46679968Sobrien return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 46779968Sobrien} 46879968Sobrien 46979968Sobrien/* 47079968Sobrien * Xdr routine to generate fhstatus 47179968Sobrien */ 47279968Sobrienint 47379968Sobrienxdr_fhs(xdrsp, nfh) 47479968Sobrien XDR *xdrsp; 47579968Sobrien nfsv2fh_t *nfh; 47679968Sobrien{ 47779968Sobrien u_long ok = 0; 47879968Sobrien 47979968Sobrien if (!xdr_long(xdrsp, &ok)) 48079968Sobrien return (0); 48179968Sobrien return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); 48279968Sobrien} 48379968Sobrien 48479968Sobrienint 48579968Sobrienxdr_mlist(xdrsp, cp) 48679968Sobrien XDR *xdrsp; 48792282Sobrien caddr_t cp; 48892282Sobrien{ 48992282Sobrien struct mountlist *mlp; 49092282Sobrien int true = 1; 49192282Sobrien int false = 0; 49279968Sobrien char *strp; 49379968Sobrien 49492282Sobrien mlp = mlhead; 49579968Sobrien while (mlp) { 49679968Sobrien if (!xdr_bool(xdrsp, &true)) 49779968Sobrien return (0); 49879968Sobrien strp = &mlp->ml_host[0]; 49979968Sobrien if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 50079968Sobrien return (0); 50179968Sobrien strp = &mlp->ml_dirp[0]; 50279968Sobrien if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 50379968Sobrien return (0); 50479968Sobrien mlp = mlp->ml_next; 50579968Sobrien } 50679968Sobrien if (!xdr_bool(xdrsp, &false)) 50779968Sobrien return (0); 50879968Sobrien return (1); 50979968Sobrien} 51079968Sobrien 51179968Sobrien/* 51279968Sobrien * Xdr conversion for export list 51379968Sobrien */ 514108746Sobrienint 51579968Sobrienxdr_explist(xdrsp, cp) 51679968Sobrien XDR *xdrsp; 51779968Sobrien caddr_t cp; 51879968Sobrien{ 51979968Sobrien struct exportlist *ep; 52079968Sobrien int false = 0; 521108746Sobrien int omask, putdef; 52279968Sobrien 52379968Sobrien omask = sigblock(sigmask(SIGHUP)); 52479968Sobrien ep = exphead; 52579968Sobrien while (ep) { 52679968Sobrien putdef = 0; 52779968Sobrien if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 52879968Sobrien goto errout; 52979968Sobrien if (ep->ex_defdir && putdef == 0 && 53079968Sobrien put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 53179968Sobrien &putdef)) 53279968Sobrien goto errout; 53379968Sobrien ep = ep->ex_next; 53479968Sobrien } 53579968Sobrien sigsetmask(omask); 53679968Sobrien if (!xdr_bool(xdrsp, &false)) 537108746Sobrien return (0); 538108746Sobrien return (1); 53979968Sobrienerrout: 540108746Sobrien sigsetmask(omask); 54179968Sobrien return (0); 54279968Sobrien} 54379968Sobrien 54479968Sobrien/* 54579968Sobrien * Called from xdr_explist() to traverse the tree and export the 54679968Sobrien * directory paths. 54779968Sobrien */ 54879968Sobrienint 54979968Sobrienput_exlist(dp, xdrsp, adp, putdefp) 55079968Sobrien struct dirlist *dp; 55179968Sobrien XDR *xdrsp; 55279968Sobrien struct dirlist *adp; 55379968Sobrien int *putdefp; 55479968Sobrien{ 55579968Sobrien struct grouplist *grp; 55679968Sobrien struct hostlist *hp; 55779968Sobrien int true = 1; 55879968Sobrien int false = 0; 55979968Sobrien int gotalldir = 0; 56079968Sobrien char *strp; 56179968Sobrien 56279968Sobrien if (dp) { 56379968Sobrien if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 56479968Sobrien return (1); 56579968Sobrien if (!xdr_bool(xdrsp, &true)) 56679968Sobrien return (1); 56779968Sobrien strp = dp->dp_dirp; 56879968Sobrien if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 56979968Sobrien return (1); 57079968Sobrien if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 57179968Sobrien gotalldir = 1; 57279968Sobrien *putdefp = 1; 57379968Sobrien } 57479968Sobrien if ((dp->dp_flag & DP_DEFSET) == 0 && 57579968Sobrien (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 57679968Sobrien hp = dp->dp_hosts; 57779968Sobrien while (hp) { 57879968Sobrien grp = hp->ht_grp; 57979968Sobrien if (grp->gr_type == GT_HOST) { 58079968Sobrien if (!xdr_bool(xdrsp, &true)) 58179968Sobrien return (1); 58279968Sobrien strp = grp->gr_ptr.gt_hostent->h_name; 58379968Sobrien if (!xdr_string(xdrsp, &strp, 58479968Sobrien RPCMNT_NAMELEN)) 58579968Sobrien return (1); 58679968Sobrien } else if (grp->gr_type == GT_NET) { 58779968Sobrien if (!xdr_bool(xdrsp, &true)) 58879968Sobrien return (1); 58979968Sobrien strp = grp->gr_ptr.gt_net.nt_name; 59079968Sobrien if (!xdr_string(xdrsp, &strp, 59179968Sobrien RPCMNT_NAMELEN)) 59279968Sobrien return (1); 59379968Sobrien } 59479968Sobrien hp = hp->ht_next; 59579968Sobrien if (gotalldir && hp == (struct hostlist *)NULL) { 59679968Sobrien hp = adp->dp_hosts; 59779968Sobrien gotalldir = 0; 59879968Sobrien } 59979968Sobrien } 60079968Sobrien } 60179968Sobrien if (!xdr_bool(xdrsp, &false)) 60279968Sobrien return (1); 60379968Sobrien if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 60479968Sobrien return (1); 60579968Sobrien } 60679968Sobrien return (0); 60779968Sobrien} 60879968Sobrien 60979968Sobrien#define LINESIZ 10240 61079968Sobrienchar line[LINESIZ]; 61179968SobrienFILE *exp_file; 61279968Sobrien 61379968Sobrien/* 61479968Sobrien * Get the export list 61579968Sobrien */ 61679968Sobrienvoid 61779968Sobrienget_exportlist() 61879968Sobrien{ 61979968Sobrien struct exportlist *ep, *ep2; 62079968Sobrien struct grouplist *grp, *tgrp; 62179968Sobrien struct exportlist **epp; 62279968Sobrien struct dirlist *dirhead; 62379968Sobrien struct statfs fsb, *fsp; 62479968Sobrien struct hostent *hpe; 62579968Sobrien struct ucred anon; 62679968Sobrien char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 62779968Sobrien int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 62879968Sobrien 62979968Sobrien /* 63079968Sobrien * First, get rid of the old list 63179968Sobrien */ 63279968Sobrien ep = exphead; 63379968Sobrien while (ep) { 63479968Sobrien ep2 = ep; 63579968Sobrien ep = ep->ex_next; 63679968Sobrien free_exp(ep2); 63779968Sobrien } 63879968Sobrien exphead = (struct exportlist *)NULL; 63979968Sobrien 64079968Sobrien grp = grphead; 64179968Sobrien while (grp) { 64279968Sobrien tgrp = grp; 64379968Sobrien grp = grp->gr_next; 64479968Sobrien free_grp(tgrp); 64579968Sobrien } 64679968Sobrien grphead = (struct grouplist *)NULL; 64779968Sobrien 64879968Sobrien /* 64979968Sobrien * And delete exports that are in the kernel for all local 65079968Sobrien * file systems. 65179968Sobrien * XXX: Should know how to handle all local exportable file systems 65279968Sobrien * instead of just MOUNT_UFS. 65379968Sobrien */ 65479968Sobrien num = getmntinfo(&fsp, MNT_NOWAIT); 65579968Sobrien for (i = 0; i < num; i++) { 65679968Sobrien union { 65779968Sobrien struct ufs_args ua; 65879968Sobrien struct iso_args ia; 65979968Sobrien struct mfs_args ma; 66079968Sobrien } targs; 66179968Sobrien 66279968Sobrien switch (fsp->f_type) { 66379968Sobrien case MOUNT_MFS: 66479968Sobrien case MOUNT_UFS: 66579968Sobrien case MOUNT_CD9660: 66679968Sobrien case MOUNT_MSDOS: 66779968Sobrien targs.ua.fspec = NULL; 66879968Sobrien targs.ua.export.ex_flags = MNT_DELEXPORT; 66979968Sobrien if (mount(fsp->f_type, fsp->f_mntonname, 67079968Sobrien fsp->f_flags | MNT_UPDATE, 67179968Sobrien (caddr_t)&targs) < 0) 67279968Sobrien syslog(LOG_ERR, "Can't delete exports for %s", 67379968Sobrien fsp->f_mntonname); 67479968Sobrien } 67579968Sobrien fsp++; 67679968Sobrien } 67779968Sobrien 67879968Sobrien /* 67979968Sobrien * Read in the exports file and build the list, calling 68079968Sobrien * mount() as we go along to push the export rules into the kernel. 68179968Sobrien */ 68279968Sobrien if ((exp_file = fopen(exname, "r")) == NULL) { 68379968Sobrien syslog(LOG_ERR, "Can't open %s", exname); 68479968Sobrien exit(2); 68579968Sobrien } 68679968Sobrien dirhead = (struct dirlist *)NULL; 68779968Sobrien while (get_line()) { 68879968Sobrien if (debug) 68979968Sobrien fprintf(stderr,"Got line %s\n",line); 69079968Sobrien cp = line; 69179968Sobrien nextfield(&cp, &endcp); 69279968Sobrien if (*cp == '#') 69379968Sobrien goto nextline; 69479968Sobrien 69579968Sobrien /* 69679968Sobrien * Set defaults. 69779968Sobrien */ 69879968Sobrien has_host = FALSE; 69979968Sobrien anon = def_anon; 70079968Sobrien exflags = MNT_EXPORTED; 70179968Sobrien got_nondir = 0; 70279968Sobrien opt_flags = 0; 70379968Sobrien ep = (struct exportlist *)NULL; 70479968Sobrien 70579968Sobrien /* 70679968Sobrien * Create new exports list entry 70779968Sobrien */ 70879968Sobrien len = endcp-cp; 70979968Sobrien tgrp = grp = get_grp(); 71079968Sobrien while (len > 0) { 71179968Sobrien if (len > RPCMNT_NAMELEN) { 71279968Sobrien getexp_err(ep, tgrp); 71379968Sobrien goto nextline; 71479968Sobrien } 71579968Sobrien if (*cp == '-') { 71679968Sobrien if (ep == (struct exportlist *)NULL) { 71779968Sobrien getexp_err(ep, tgrp); 71879968Sobrien goto nextline; 71979968Sobrien } 72079968Sobrien if (debug) 72179968Sobrien fprintf(stderr, "doing opt %s\n", cp); 72279968Sobrien got_nondir = 1; 72379968Sobrien if (do_opt(&cp, &endcp, ep, grp, &has_host, 72479968Sobrien &exflags, &anon)) { 72579968Sobrien getexp_err(ep, tgrp); 72679968Sobrien goto nextline; 72779968Sobrien } 72879968Sobrien } else if (*cp == '/') { 72979968Sobrien savedc = *endcp; 73079968Sobrien *endcp = '\0'; 73179968Sobrien if (check_dirpath(cp) && 73279968Sobrien statfs(cp, &fsb) >= 0) { 73379968Sobrien if (got_nondir) { 73479968Sobrien syslog(LOG_ERR, "Dirs must be first"); 73579968Sobrien getexp_err(ep, tgrp); 73679968Sobrien goto nextline; 73779968Sobrien } 73879968Sobrien if (ep) { 73979968Sobrien if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 74079968Sobrien ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 74179968Sobrien getexp_err(ep, tgrp); 74279968Sobrien goto nextline; 74379968Sobrien } 74479968Sobrien } else { 74592282Sobrien /* 74692282Sobrien * See if this directory is already 74792282Sobrien * in the list. 74892282Sobrien */ 74992282Sobrien ep = ex_search(&fsb.f_fsid); 75092282Sobrien if (ep == (struct exportlist *)NULL) { 75192282Sobrien ep = get_exp(); 75292282Sobrien ep->ex_fs = fsb.f_fsid; 75379968Sobrien ep->ex_fsdir = (char *) 75492282Sobrien malloc(strlen(fsb.f_mntonname) + 1); 75579968Sobrien if (ep->ex_fsdir) 75679968Sobrien strcpy(ep->ex_fsdir, 75779968Sobrien fsb.f_mntonname); 75879968Sobrien else 75979968Sobrien out_of_mem(); 76079968Sobrien if (debug) 76179968Sobrien fprintf(stderr, 76279968Sobrien "Making new ep fs=0x%x,0x%x\n", 76379968Sobrien fsb.f_fsid.val[0], 76479968Sobrien fsb.f_fsid.val[1]); 76579968Sobrien } else if (debug) 76679968Sobrien fprintf(stderr, 76779968Sobrien "Found ep fs=0x%x,0x%x\n", 76879968Sobrien fsb.f_fsid.val[0], 76979968Sobrien fsb.f_fsid.val[1]); 77079968Sobrien } 77179968Sobrien 77279968Sobrien /* 77379968Sobrien * Add dirpath to export mount point. 77479968Sobrien */ 77579968Sobrien dirp = add_expdir(&dirhead, cp, len); 77679968Sobrien dirplen = len; 77779968Sobrien } else { 77879968Sobrien getexp_err(ep, tgrp); 77979968Sobrien goto nextline; 78079968Sobrien } 78179968Sobrien *endcp = savedc; 78279968Sobrien } else { 78379968Sobrien savedc = *endcp; 78479968Sobrien *endcp = '\0'; 78579968Sobrien got_nondir = 1; 78679968Sobrien if (ep == (struct exportlist *)NULL) { 78779968Sobrien getexp_err(ep, tgrp); 78879968Sobrien goto nextline; 78979968Sobrien } 79079968Sobrien 79179968Sobrien /* 79279968Sobrien * Get the host or netgroup. 79379968Sobrien */ 79479968Sobrien setnetgrent(cp); 79579968Sobrien netgrp = getnetgrent(&hst, &usr, &dom); 79679968Sobrien do { 79779968Sobrien if (has_host) { 79879968Sobrien grp->gr_next = get_grp(); 79979968Sobrien grp = grp->gr_next; 80079968Sobrien } 80179968Sobrien if (netgrp) { 80279968Sobrien if (get_host(hst, grp, tgrp)) { 80379968Sobrien syslog(LOG_ERR, "Bad netgroup %s", cp); 80479968Sobrien getexp_err(ep, tgrp); 80579968Sobrien goto nextline; 80679968Sobrien } 80779968Sobrien } else if (get_host(cp, grp, tgrp)) { 80879968Sobrien getexp_err(ep, tgrp); 80992282Sobrien goto nextline; 810133936Sobrien } 81179968Sobrien has_host = TRUE; 81279968Sobrien } while (netgrp && getnetgrent(&hst, &usr, &dom)); 81379968Sobrien endnetgrent(); 81479968Sobrien *endcp = savedc; 81579968Sobrien } 81692282Sobrien cp = endcp; 81792282Sobrien nextfield(&cp, &endcp); 81892282Sobrien len = endcp - cp; 81992282Sobrien } 82092282Sobrien if (check_options(dirhead)) { 82192282Sobrien getexp_err(ep, tgrp); 82292282Sobrien goto nextline; 82392282Sobrien } 82492282Sobrien if (!has_host) { 82592282Sobrien grp->gr_type = GT_HOST; 82679968Sobrien if (debug) 82779968Sobrien fprintf(stderr,"Adding a default entry\n"); 82879968Sobrien /* add a default group and make the grp list NULL */ 82979968Sobrien hpe = (struct hostent *)malloc(sizeof(struct hostent)); 83079968Sobrien if (hpe == (struct hostent *)NULL) 83179968Sobrien out_of_mem(); 83279968Sobrien hpe->h_name = "Default"; 83379968Sobrien hpe->h_addrtype = AF_INET; 83479968Sobrien hpe->h_length = sizeof (u_long); 83579968Sobrien hpe->h_addr_list = (char **)NULL; 83679968Sobrien grp->gr_ptr.gt_hostent = hpe; 83779968Sobrien 83879968Sobrien /* 83979968Sobrien * Don't allow a network export coincide with a list of 84079968Sobrien * host(s) on the same line. 84179968Sobrien */ 84279968Sobrien } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 84379968Sobrien getexp_err(ep, tgrp); 84479968Sobrien goto nextline; 84579968Sobrien } 84679968Sobrien 84779968Sobrien /* 84879968Sobrien * Loop through hosts, pushing the exports into the kernel. 84979968Sobrien * After loop, tgrp points to the start of the list and 85079968Sobrien * grp points to the last entry in the list. 851110242Sobrien */ 852110242Sobrien grp = tgrp; 853110242Sobrien do { 854110242Sobrien if (do_mount(ep, grp, exflags, &anon, dirp, 855110242Sobrien dirplen, &fsb)) { 856110242Sobrien getexp_err(ep, tgrp); 857110242Sobrien goto nextline; 858110242Sobrien } 859110242Sobrien } while (grp->gr_next && (grp = grp->gr_next)); 860110242Sobrien 861110242Sobrien /* 862110242Sobrien * Success. Update the data structures. 863110242Sobrien */ 864110242Sobrien if (has_host) { 865110242Sobrien hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS)); 866110242Sobrien grp->gr_next = grphead; 867110242Sobrien grphead = tgrp; 868110242Sobrien } else { 869110242Sobrien hang_dirp(dirhead, (struct grouplist *)NULL, ep, 870110242Sobrien (opt_flags & OP_ALLDIRS)); 871110242Sobrien free_grp(grp); 872110242Sobrien } 873110242Sobrien dirhead = (struct dirlist *)NULL; 874110242Sobrien if ((ep->ex_flag & EX_LINKED) == 0) { 875110242Sobrien ep2 = exphead; 876110242Sobrien epp = &exphead; 877110242Sobrien 878110242Sobrien /* 879110242Sobrien * Insert in the list in alphabetical order. 880110242Sobrien */ 881110242Sobrien while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 882110242Sobrien epp = &ep2->ex_next; 883110242Sobrien ep2 = ep2->ex_next; 884110242Sobrien } 885110242Sobrien if (ep2) 886110242Sobrien ep->ex_next = ep2; 887110242Sobrien *epp = ep; 888110242Sobrien ep->ex_flag |= EX_LINKED; 889110242Sobrien } 890110242Sobriennextline: 891110242Sobrien if (dirhead) { 892110242Sobrien free_dir(dirhead); 893110242Sobrien dirhead = (struct dirlist *)NULL; 894110242Sobrien } 895110242Sobrien } 896110242Sobrien fclose(exp_file); 897110242Sobrien} 898110242Sobrien 899110242Sobrien/* 900110242Sobrien * Allocate an export list element 901110242Sobrien */ 902110242Sobrienstruct exportlist * 903110242Sobrienget_exp() 904110242Sobrien{ 905110242Sobrien struct exportlist *ep; 906110242Sobrien 907110242Sobrien ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 908110242Sobrien if (ep == (struct exportlist *)NULL) 909110242Sobrien out_of_mem(); 910110242Sobrien bzero((caddr_t)ep, sizeof (struct exportlist)); 911110242Sobrien return (ep); 912110242Sobrien} 913110242Sobrien 914110242Sobrien/* 915110242Sobrien * Allocate a group list element 916110242Sobrien */ 917110242Sobrienstruct grouplist * 918110242Sobrienget_grp() 919110242Sobrien{ 920110242Sobrien struct grouplist *gp; 921110242Sobrien 922110242Sobrien gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 923110242Sobrien if (gp == (struct grouplist *)NULL) 924110242Sobrien out_of_mem(); 925110242Sobrien bzero((caddr_t)gp, sizeof (struct grouplist)); 926110242Sobrien return (gp); 927110242Sobrien} 928110242Sobrien 929110242Sobrien/* 930110242Sobrien * Clean up upon an error in get_exportlist(). 931110242Sobrien */ 932110242Sobrienvoid 933110242Sobriengetexp_err(ep, grp) 934110242Sobrien struct exportlist *ep; 935110242Sobrien struct grouplist *grp; 936110242Sobrien{ 937110242Sobrien struct grouplist *tgrp; 938110242Sobrien 939110242Sobrien syslog(LOG_ERR, "Bad exports list line %s", line); 940110242Sobrien if (ep && (ep->ex_flag & EX_LINKED) == 0) 941110242Sobrien free_exp(ep); 942110242Sobrien while (grp) { 943110242Sobrien tgrp = grp; 944110242Sobrien grp = grp->gr_next; 945110242Sobrien free_grp(tgrp); 946110242Sobrien } 947110242Sobrien} 948110242Sobrien 949110242Sobrien/* 950110242Sobrien * Search the export list for a matching fs. 951110242Sobrien */ 952110242Sobrienstruct exportlist * 953110242Sobrienex_search(fsid) 954110242Sobrien fsid_t *fsid; 955110242Sobrien{ 956110242Sobrien struct exportlist *ep; 957110242Sobrien 958110242Sobrien ep = exphead; 959110242Sobrien while (ep) { 960110242Sobrien if (ep->ex_fs.val[0] == fsid->val[0] && 961110242Sobrien ep->ex_fs.val[1] == fsid->val[1]) 962110242Sobrien return (ep); 963110242Sobrien ep = ep->ex_next; 964110242Sobrien } 965110242Sobrien return (ep); 966110242Sobrien} 967110242Sobrien 968110242Sobrien/* 969110242Sobrien * Add a directory path to the list. 970110242Sobrien */ 971110242Sobrienchar * 972110242Sobrienadd_expdir(dpp, cp, len) 973110242Sobrien struct dirlist **dpp; 974 char *cp; 975 int len; 976{ 977 struct dirlist *dp; 978 979 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 980 dp->dp_left = *dpp; 981 dp->dp_right = (struct dirlist *)NULL; 982 dp->dp_flag = 0; 983 dp->dp_hosts = (struct hostlist *)NULL; 984 strcpy(dp->dp_dirp, cp); 985 *dpp = dp; 986 return (dp->dp_dirp); 987} 988 989/* 990 * Hang the dir list element off the dirpath binary tree as required 991 * and update the entry for host. 992 */ 993void 994hang_dirp(dp, grp, ep, alldirs) 995 struct dirlist *dp; 996 struct grouplist *grp; 997 struct exportlist *ep; 998 int alldirs; 999{ 1000 struct hostlist *hp; 1001 struct dirlist *dp2; 1002 1003 if (alldirs) { 1004 if (ep->ex_defdir) 1005 free((caddr_t)dp); 1006 else 1007 ep->ex_defdir = dp; 1008 if (grp == (struct grouplist *)NULL) 1009 ep->ex_defdir->dp_flag |= DP_DEFSET; 1010 else while (grp) { 1011 hp = get_ht(); 1012 hp->ht_grp = grp; 1013 hp->ht_next = ep->ex_defdir->dp_hosts; 1014 ep->ex_defdir->dp_hosts = hp; 1015 grp = grp->gr_next; 1016 } 1017 } else { 1018 1019 /* 1020 * Loop throught the directories adding them to the tree. 1021 */ 1022 while (dp) { 1023 dp2 = dp->dp_left; 1024 add_dlist(&ep->ex_dirl, dp, grp); 1025 dp = dp2; 1026 } 1027 } 1028} 1029 1030/* 1031 * Traverse the binary tree either updating a node that is already there 1032 * for the new directory or adding the new node. 1033 */ 1034void 1035add_dlist(dpp, newdp, grp) 1036 struct dirlist **dpp; 1037 struct dirlist *newdp; 1038 struct grouplist *grp; 1039{ 1040 struct dirlist *dp; 1041 struct hostlist *hp; 1042 int cmp; 1043 1044 dp = *dpp; 1045 if (dp) { 1046 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1047 if (cmp > 0) { 1048 add_dlist(&dp->dp_left, newdp, grp); 1049 return; 1050 } else if (cmp < 0) { 1051 add_dlist(&dp->dp_right, newdp, grp); 1052 return; 1053 } else 1054 free((caddr_t)newdp); 1055 } else { 1056 dp = newdp; 1057 dp->dp_left = (struct dirlist *)NULL; 1058 *dpp = dp; 1059 } 1060 if (grp) { 1061 1062 /* 1063 * Hang all of the host(s) off of the directory point. 1064 */ 1065 do { 1066 hp = get_ht(); 1067 hp->ht_grp = grp; 1068 hp->ht_next = dp->dp_hosts; 1069 dp->dp_hosts = hp; 1070 grp = grp->gr_next; 1071 } while (grp); 1072 } else 1073 dp->dp_flag |= DP_DEFSET; 1074} 1075 1076/* 1077 * Search for a dirpath on the export point. 1078 */ 1079struct dirlist * 1080dirp_search(dp, dirpath) 1081 struct dirlist *dp; 1082 char *dirpath; 1083{ 1084 int cmp; 1085 1086 if (dp) { 1087 cmp = strcmp(dp->dp_dirp, dirpath); 1088 if (cmp > 0) 1089 return (dirp_search(dp->dp_left, dirpath)); 1090 else if (cmp < 0) 1091 return (dirp_search(dp->dp_right, dirpath)); 1092 else 1093 return (dp); 1094 } 1095 return (dp); 1096} 1097 1098/* 1099 * Scan for a host match in a directory tree. 1100 */ 1101int 1102chk_host(dp, saddr, defsetp) 1103 struct dirlist *dp; 1104 u_long saddr; 1105 int *defsetp; 1106{ 1107 struct hostlist *hp; 1108 struct grouplist *grp; 1109 u_long **addrp; 1110 1111 if (dp) { 1112 if (dp->dp_flag & DP_DEFSET) 1113 *defsetp = 1; 1114 hp = dp->dp_hosts; 1115 while (hp) { 1116 grp = hp->ht_grp; 1117 switch (grp->gr_type) { 1118 case GT_HOST: 1119 addrp = (u_long **) 1120 grp->gr_ptr.gt_hostent->h_addr_list; 1121 while (*addrp) { 1122 if (**addrp == saddr) 1123 return (1); 1124 addrp++; 1125 } 1126 break; 1127 case GT_NET: 1128 if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 1129 grp->gr_ptr.gt_net.nt_net) 1130 return (1); 1131 break; 1132 }; 1133 hp = hp->ht_next; 1134 } 1135 } 1136 return (0); 1137} 1138 1139/* 1140 * Scan tree for a host that matches the address. 1141 */ 1142int 1143scan_tree(dp, saddr) 1144 struct dirlist *dp; 1145 u_long saddr; 1146{ 1147 int defset; 1148 1149 if (dp) { 1150 if (scan_tree(dp->dp_left, saddr)) 1151 return (1); 1152 if (chk_host(dp, saddr, &defset)) 1153 return (1); 1154 if (scan_tree(dp->dp_right, saddr)) 1155 return (1); 1156 } 1157 return (0); 1158} 1159 1160/* 1161 * Traverse the dirlist tree and free it up. 1162 */ 1163void 1164free_dir(dp) 1165 struct dirlist *dp; 1166{ 1167 1168 if (dp) { 1169 free_dir(dp->dp_left); 1170 free_dir(dp->dp_right); 1171 free_host(dp->dp_hosts); 1172 free((caddr_t)dp); 1173 } 1174} 1175 1176/* 1177 * Parse the option string and update fields. 1178 * Option arguments may either be -<option>=<value> or 1179 * -<option> <value> 1180 */ 1181int 1182do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1183 char **cpp, **endcpp; 1184 struct exportlist *ep; 1185 struct grouplist *grp; 1186 int *has_hostp; 1187 int *exflagsp; 1188 struct ucred *cr; 1189{ 1190 char *cpoptarg, *cpoptend; 1191 char *cp, *endcp, *cpopt, savedc, savedc2; 1192 int allflag, usedarg; 1193 1194 cpopt = *cpp; 1195 cpopt++; 1196 cp = *endcpp; 1197 savedc = *cp; 1198 *cp = '\0'; 1199 while (cpopt && *cpopt) { 1200 allflag = 1; 1201 usedarg = -2; 1202 if (cpoptend = index(cpopt, ',')) { 1203 *cpoptend++ = '\0'; 1204 if (cpoptarg = index(cpopt, '=')) 1205 *cpoptarg++ = '\0'; 1206 } else { 1207 if (cpoptarg = index(cpopt, '=')) 1208 *cpoptarg++ = '\0'; 1209 else { 1210 *cp = savedc; 1211 nextfield(&cp, &endcp); 1212 **endcpp = '\0'; 1213 if (endcp > cp && *cp != '-') { 1214 cpoptarg = cp; 1215 savedc2 = *endcp; 1216 *endcp = '\0'; 1217 usedarg = 0; 1218 } 1219 } 1220 } 1221 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1222 *exflagsp |= MNT_EXRDONLY; 1223 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1224 !(allflag = strcmp(cpopt, "mapall")) || 1225 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1226 usedarg++; 1227 parsecred(cpoptarg, cr); 1228 if (allflag == 0) { 1229 *exflagsp |= MNT_EXPORTANON; 1230 opt_flags |= OP_MAPALL; 1231 } else 1232 opt_flags |= OP_MAPROOT; 1233 } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 1234 *exflagsp |= MNT_EXKERB; 1235 opt_flags |= OP_KERB; 1236 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1237 !strcmp(cpopt, "m"))) { 1238 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1239 syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 1240 return (1); 1241 } 1242 usedarg++; 1243 opt_flags |= OP_MASK; 1244 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1245 !strcmp(cpopt, "n"))) { 1246 if (grp->gr_type != GT_NULL) { 1247 syslog(LOG_ERR, "Network/host conflict"); 1248 return (1); 1249 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1250 syslog(LOG_ERR, "Bad net: %s", cpoptarg); 1251 return (1); 1252 } 1253 grp->gr_type = GT_NET; 1254 *has_hostp = 1; 1255 usedarg++; 1256 opt_flags |= OP_NET; 1257 } else if (!strcmp(cpopt, "alldirs")) { 1258 opt_flags |= OP_ALLDIRS; 1259#ifdef ISO 1260 } else if (cpoptarg && !strcmp(cpopt, "iso")) { 1261 if (get_isoaddr(cpoptarg, grp)) { 1262 syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 1263 return (1); 1264 } 1265 *has_hostp = 1; 1266 usedarg++; 1267 opt_flags |= OP_ISO; 1268#endif /* ISO */ 1269 } else { 1270 syslog(LOG_ERR, "Bad opt %s", cpopt); 1271 return (1); 1272 } 1273 if (usedarg >= 0) { 1274 *endcp = savedc2; 1275 **endcpp = savedc; 1276 if (usedarg > 0) { 1277 *cpp = cp; 1278 *endcpp = endcp; 1279 } 1280 return (0); 1281 } 1282 cpopt = cpoptend; 1283 } 1284 **endcpp = savedc; 1285 return (0); 1286} 1287 1288/* 1289 * Translate a character string to the corresponding list of network 1290 * addresses for a hostname. 1291 */ 1292int 1293get_host(cp, grp, tgrp) 1294 char *cp; 1295 struct grouplist *grp; 1296 struct grouplist *tgrp; 1297{ 1298 struct grouplist *checkgrp; 1299 struct hostent *hp, *nhp; 1300 char **addrp, **naddrp; 1301 struct hostent t_host; 1302 int i; 1303 u_long saddr; 1304 char *aptr[2]; 1305 1306 if (grp->gr_type != GT_NULL) 1307 return (1); 1308 if ((hp = gethostbyname(cp)) == NULL) { 1309 if (isdigit(*cp)) { 1310 saddr = inet_addr(cp); 1311 if (saddr == -1) { 1312 syslog(LOG_ERR, "Inet_addr failed"); 1313 return (1); 1314 } 1315 if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 1316 AF_INET)) == NULL) { 1317 hp = &t_host; 1318 hp->h_name = cp; 1319 hp->h_addrtype = AF_INET; 1320 hp->h_length = sizeof (u_long); 1321 hp->h_addr_list = aptr; 1322 aptr[0] = (char *)&saddr; 1323 aptr[1] = (char *)NULL; 1324 } 1325 } else { 1326 syslog(LOG_ERR, "Gethostbyname failed"); 1327 return (1); 1328 } 1329 } 1330 /* 1331 * Sanity check: make sure we don't already have an entry 1332 * for this host in the grouplist. 1333 */ 1334 checkgrp = tgrp; 1335 while (checkgrp) { 1336 if (checkgrp->gr_ptr.gt_hostent != NULL && 1337 !strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name)) { 1338 grp->gr_type = GT_IGNORE; 1339 return(0); 1340 } 1341 checkgrp = checkgrp->gr_next; 1342 } 1343 1344 grp->gr_type = GT_HOST; 1345 nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 1346 malloc(sizeof(struct hostent)); 1347 if (nhp == (struct hostent *)NULL) 1348 out_of_mem(); 1349 bcopy((caddr_t)hp, (caddr_t)nhp, 1350 sizeof(struct hostent)); 1351 i = strlen(hp->h_name)+1; 1352 nhp->h_name = (char *)malloc(i); 1353 if (nhp->h_name == (char *)NULL) 1354 out_of_mem(); 1355 bcopy(hp->h_name, nhp->h_name, i); 1356 addrp = hp->h_addr_list; 1357 i = 1; 1358 while (*addrp++) 1359 i++; 1360 naddrp = nhp->h_addr_list = (char **) 1361 malloc(i*sizeof(char *)); 1362 if (naddrp == (char **)NULL) 1363 out_of_mem(); 1364 addrp = hp->h_addr_list; 1365 while (*addrp) { 1366 *naddrp = (char *) 1367 malloc(hp->h_length); 1368 if (*naddrp == (char *)NULL) 1369 out_of_mem(); 1370 bcopy(*addrp, *naddrp, 1371 hp->h_length); 1372 addrp++; 1373 naddrp++; 1374 } 1375 *naddrp = (char *)NULL; 1376 if (debug) 1377 fprintf(stderr, "got host %s\n", hp->h_name); 1378 return (0); 1379} 1380 1381/* 1382 * Free up an exports list component 1383 */ 1384void 1385free_exp(ep) 1386 struct exportlist *ep; 1387{ 1388 1389 if (ep->ex_defdir) { 1390 free_host(ep->ex_defdir->dp_hosts); 1391 free((caddr_t)ep->ex_defdir); 1392 } 1393 if (ep->ex_fsdir) 1394 free(ep->ex_fsdir); 1395 free_dir(ep->ex_dirl); 1396 free((caddr_t)ep); 1397} 1398 1399/* 1400 * Free hosts. 1401 */ 1402void 1403free_host(hp) 1404 struct hostlist *hp; 1405{ 1406 struct hostlist *hp2; 1407 1408 while (hp) { 1409 hp2 = hp; 1410 hp = hp->ht_next; 1411 free((caddr_t)hp2); 1412 } 1413} 1414 1415struct hostlist * 1416get_ht() 1417{ 1418 struct hostlist *hp; 1419 1420 hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 1421 if (hp == (struct hostlist *)NULL) 1422 out_of_mem(); 1423 hp->ht_next = (struct hostlist *)NULL; 1424 return (hp); 1425} 1426 1427#ifdef ISO 1428/* 1429 * Translate an iso address. 1430 */ 1431get_isoaddr(cp, grp) 1432 char *cp; 1433 struct grouplist *grp; 1434{ 1435 struct iso_addr *isop; 1436 struct sockaddr_iso *isoaddr; 1437 1438 if (grp->gr_type != GT_NULL) 1439 return (1); 1440 if ((isop = iso_addr(cp)) == NULL) { 1441 syslog(LOG_ERR, 1442 "iso_addr failed, ignored"); 1443 return (1); 1444 } 1445 isoaddr = (struct sockaddr_iso *) 1446 malloc(sizeof (struct sockaddr_iso)); 1447 if (isoaddr == (struct sockaddr_iso *)NULL) 1448 out_of_mem(); 1449 bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 1450 bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 1451 sizeof (struct iso_addr)); 1452 isoaddr->siso_len = sizeof (struct sockaddr_iso); 1453 isoaddr->siso_family = AF_ISO; 1454 grp->gr_type = GT_ISO; 1455 grp->gr_ptr.gt_isoaddr = isoaddr; 1456 return (0); 1457} 1458#endif /* ISO */ 1459 1460/* 1461 * Out of memory, fatal 1462 */ 1463void 1464out_of_mem() 1465{ 1466 1467 syslog(LOG_ERR, "Out of memory"); 1468 exit(2); 1469} 1470 1471/* 1472 * Do the mount syscall with the update flag to push the export info into 1473 * the kernel. 1474 */ 1475int 1476do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 1477 struct exportlist *ep; 1478 struct grouplist *grp; 1479 int exflags; 1480 struct ucred *anoncrp; 1481 char *dirp; 1482 int dirplen; 1483 struct statfs *fsb; 1484{ 1485 char *cp = (char *)NULL; 1486 u_long **addrp; 1487 int done; 1488 char savedc = '\0'; 1489 struct sockaddr_in sin, imask; 1490 union { 1491 struct ufs_args ua; 1492 struct iso_args ia; 1493 struct mfs_args ma; 1494 } args; 1495 u_long net; 1496 1497 args.ua.fspec = 0; 1498 args.ua.export.ex_flags = exflags; 1499 args.ua.export.ex_anon = *anoncrp; 1500 bzero((char *)&sin, sizeof(sin)); 1501 bzero((char *)&imask, sizeof(imask)); 1502 sin.sin_family = AF_INET; 1503 sin.sin_len = sizeof(sin); 1504 imask.sin_family = AF_INET; 1505 imask.sin_len = sizeof(sin); 1506 if (grp->gr_type == GT_HOST) 1507 addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 1508 else 1509 addrp = (u_long **)NULL; 1510 done = FALSE; 1511 while (!done) { 1512 switch (grp->gr_type) { 1513 case GT_HOST: 1514 if (addrp) { 1515 sin.sin_addr.s_addr = **addrp; 1516 args.ua.export.ex_addrlen = sizeof(sin); 1517 } else 1518 args.ua.export.ex_addrlen = 0; 1519 args.ua.export.ex_addr = (struct sockaddr *)&sin; 1520 args.ua.export.ex_masklen = 0; 1521 break; 1522 case GT_NET: 1523 if (grp->gr_ptr.gt_net.nt_mask) 1524 imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 1525 else { 1526 net = ntohl(grp->gr_ptr.gt_net.nt_net); 1527 if (IN_CLASSA(net)) 1528 imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 1529 else if (IN_CLASSB(net)) 1530 imask.sin_addr.s_addr = 1531 inet_addr("255.255.0.0"); 1532 else 1533 imask.sin_addr.s_addr = 1534 inet_addr("255.255.255.0"); 1535 grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 1536 } 1537 sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 1538 args.ua.export.ex_addr = (struct sockaddr *)&sin; 1539 args.ua.export.ex_addrlen = sizeof (sin); 1540 args.ua.export.ex_mask = (struct sockaddr *)&imask; 1541 args.ua.export.ex_masklen = sizeof (imask); 1542 break; 1543#ifdef ISO 1544 case GT_ISO: 1545 args.ua.export.ex_addr = 1546 (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 1547 args.ua.export.ex_addrlen = 1548 sizeof(struct sockaddr_iso); 1549 args.ua.export.ex_masklen = 0; 1550 break; 1551#endif /* ISO */ 1552 case GT_IGNORE: 1553 return(0); 1554 break; 1555 default: 1556 syslog(LOG_ERR, "Bad grouptype"); 1557 if (cp) 1558 *cp = savedc; 1559 return (1); 1560 }; 1561 1562 /* 1563 * XXX: 1564 * Maybe I should just use the fsb->f_mntonname path instead 1565 * of looping back up the dirp to the mount point?? 1566 * Also, needs to know how to export all types of local 1567 * exportable file systems and not just MOUNT_UFS. 1568 */ 1569 while (mount(fsb->f_type, dirp, 1570 fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 1571 if (cp) 1572 *cp-- = savedc; 1573 else 1574 cp = dirp + dirplen - 1; 1575 if (errno == EPERM) { 1576 syslog(LOG_ERR, 1577 "Can't change attributes for %s.\n", dirp); 1578 return (1); 1579 } 1580 if (opt_flags & OP_ALLDIRS) { 1581 syslog(LOG_ERR, "Could not remount %s: %m", 1582 dirp); 1583 return (1); 1584 } 1585 /* back up over the last component */ 1586 while (*cp == '/' && cp > dirp) 1587 cp--; 1588 while (*(cp - 1) != '/' && cp > dirp) 1589 cp--; 1590 if (cp == dirp) { 1591 if (debug) 1592 fprintf(stderr,"mnt unsucc\n"); 1593 syslog(LOG_ERR, "Can't export %s", dirp); 1594 return (1); 1595 } 1596 savedc = *cp; 1597 *cp = '\0'; 1598 } 1599 if (addrp) { 1600 ++addrp; 1601 if (*addrp == (u_long *)NULL) 1602 done = TRUE; 1603 } else 1604 done = TRUE; 1605 } 1606 if (cp) 1607 *cp = savedc; 1608 return (0); 1609} 1610 1611/* 1612 * Translate a net address. 1613 */ 1614int 1615get_net(cp, net, maskflg) 1616 char *cp; 1617 struct netmsk *net; 1618 int maskflg; 1619{ 1620 struct netent *np; 1621 long netaddr; 1622 struct in_addr inetaddr, inetaddr2; 1623 char *name; 1624 1625 if (np = getnetbyname(cp)) 1626 inetaddr = inet_makeaddr(np->n_net, 0); 1627 else if (isdigit(*cp)) { 1628 if ((netaddr = inet_network(cp)) == -1) 1629 return (1); 1630 inetaddr = inet_makeaddr(netaddr, 0); 1631 /* 1632 * Due to arbritrary subnet masks, you don't know how many 1633 * bits to shift the address to make it into a network, 1634 * however you do know how to make a network address into 1635 * a host with host == 0 and then compare them. 1636 * (What a pest) 1637 */ 1638 if (!maskflg) { 1639 setnetent(0); 1640 while (np = getnetent()) { 1641 inetaddr2 = inet_makeaddr(np->n_net, 0); 1642 if (inetaddr2.s_addr == inetaddr.s_addr) 1643 break; 1644 } 1645 endnetent(); 1646 } 1647 } else 1648 return (1); 1649 if (maskflg) 1650 net->nt_mask = inetaddr.s_addr; 1651 else { 1652 if (np) 1653 name = np->n_name; 1654 else 1655 name = inet_ntoa(inetaddr); 1656 net->nt_name = (char *)malloc(strlen(name) + 1); 1657 if (net->nt_name == (char *)NULL) 1658 out_of_mem(); 1659 strcpy(net->nt_name, name); 1660 net->nt_net = inetaddr.s_addr; 1661 } 1662 return (0); 1663} 1664 1665/* 1666 * Parse out the next white space separated field 1667 */ 1668void 1669nextfield(cp, endcp) 1670 char **cp; 1671 char **endcp; 1672{ 1673 char *p; 1674 1675 p = *cp; 1676 while (*p == ' ' || *p == '\t') 1677 p++; 1678 if (*p == '\n' || *p == '\0') 1679 *cp = *endcp = p; 1680 else { 1681 *cp = p++; 1682 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 1683 p++; 1684 *endcp = p; 1685 } 1686} 1687 1688/* 1689 * Get an exports file line. Skip over blank lines and handle line 1690 * continuations. 1691 */ 1692int 1693get_line() 1694{ 1695 char *p, *cp; 1696 int len; 1697 int totlen, cont_line; 1698 1699 /* 1700 * Loop around ignoring blank lines and getting all continuation lines. 1701 */ 1702 p = line; 1703 totlen = 0; 1704 do { 1705 if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 1706 return (0); 1707 len = strlen(p); 1708 cp = p + len - 1; 1709 cont_line = 0; 1710 while (cp >= p && 1711 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 1712 if (*cp == '\\') 1713 cont_line = 1; 1714 cp--; 1715 len--; 1716 } 1717 *++cp = '\0'; 1718 if (len > 0) { 1719 totlen += len; 1720 if (totlen >= LINESIZ) { 1721 syslog(LOG_ERR, "Exports line too long"); 1722 exit(2); 1723 } 1724 p = cp; 1725 } 1726 } while (totlen == 0 || cont_line); 1727 return (1); 1728} 1729 1730/* 1731 * Parse a description of a credential. 1732 */ 1733void 1734parsecred(namelist, cr) 1735 char *namelist; 1736 struct ucred *cr; 1737{ 1738 char *name; 1739 int cnt; 1740 char *names; 1741 struct passwd *pw; 1742 struct group *gr; 1743 int ngroups, groups[NGROUPS + 1]; 1744 1745 /* 1746 * Set up the unpriviledged user. 1747 */ 1748 cr->cr_ref = 1; 1749 cr->cr_uid = -2; 1750 cr->cr_groups[0] = -2; 1751 cr->cr_ngroups = 1; 1752 /* 1753 * Get the user's password table entry. 1754 */ 1755 names = strsep(&namelist, " \t\n"); 1756 name = strsep(&names, ":"); 1757 if (isdigit(*name) || *name == '-') 1758 pw = getpwuid(atoi(name)); 1759 else 1760 pw = getpwnam(name); 1761 /* 1762 * Credentials specified as those of a user. 1763 */ 1764 if (names == NULL) { 1765 if (pw == NULL) { 1766 syslog(LOG_ERR, "Unknown user: %s", name); 1767 return; 1768 } 1769 cr->cr_uid = pw->pw_uid; 1770 ngroups = NGROUPS + 1; 1771 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 1772 syslog(LOG_ERR, "Too many groups"); 1773 /* 1774 * Convert from int's to gid_t's and compress out duplicate 1775 */ 1776 cr->cr_ngroups = ngroups - 1; 1777 cr->cr_groups[0] = groups[0]; 1778 for (cnt = 2; cnt < ngroups; cnt++) 1779 cr->cr_groups[cnt - 1] = groups[cnt]; 1780 return; 1781 } 1782 /* 1783 * Explicit credential specified as a colon separated list: 1784 * uid:gid:gid:... 1785 */ 1786 if (pw != NULL) 1787 cr->cr_uid = pw->pw_uid; 1788 else if (isdigit(*name) || *name == '-') 1789 cr->cr_uid = atoi(name); 1790 else { 1791 syslog(LOG_ERR, "Unknown user: %s", name); 1792 return; 1793 } 1794 cr->cr_ngroups = 0; 1795 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 1796 name = strsep(&names, ":"); 1797 if (isdigit(*name) || *name == '-') { 1798 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 1799 } else { 1800 if ((gr = getgrnam(name)) == NULL) { 1801 syslog(LOG_ERR, "Unknown group: %s", name); 1802 continue; 1803 } 1804 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 1805 } 1806 } 1807 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 1808 syslog(LOG_ERR, "Too many groups"); 1809} 1810 1811#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 1812/* 1813 * Routines that maintain the remote mounttab 1814 */ 1815void 1816get_mountlist() 1817{ 1818 struct mountlist *mlp, **mlpp; 1819 char *eos, *dirp; 1820 int len; 1821 char str[STRSIZ]; 1822 FILE *mlfile; 1823 1824 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 1825 syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 1826 return; 1827 } 1828 mlpp = &mlhead; 1829 while (fgets(str, STRSIZ, mlfile) != NULL) { 1830 if ((dirp = index(str, '\t')) == NULL && 1831 (dirp = index(str, ' ')) == NULL) 1832 continue; 1833 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1834 len = dirp-str; 1835 if (len > RPCMNT_NAMELEN) 1836 len = RPCMNT_NAMELEN; 1837 bcopy(str, mlp->ml_host, len); 1838 mlp->ml_host[len] = '\0'; 1839 while (*dirp == '\t' || *dirp == ' ') 1840 dirp++; 1841 if ((eos = index(dirp, '\t')) == NULL && 1842 (eos = index(dirp, ' ')) == NULL && 1843 (eos = index(dirp, '\n')) == NULL) 1844 len = strlen(dirp); 1845 else 1846 len = eos-dirp; 1847 if (len > RPCMNT_PATHLEN) 1848 len = RPCMNT_PATHLEN; 1849 bcopy(dirp, mlp->ml_dirp, len); 1850 mlp->ml_dirp[len] = '\0'; 1851 mlp->ml_next = (struct mountlist *)NULL; 1852 *mlpp = mlp; 1853 mlpp = &mlp->ml_next; 1854 } 1855 fclose(mlfile); 1856} 1857 1858void 1859del_mlist(hostp, dirp) 1860 char *hostp, *dirp; 1861{ 1862 struct mountlist *mlp, **mlpp; 1863 struct mountlist *mlp2; 1864 FILE *mlfile; 1865 int fnd = 0; 1866 1867 mlpp = &mlhead; 1868 mlp = mlhead; 1869 while (mlp) { 1870 if (!strcmp(mlp->ml_host, hostp) && 1871 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 1872 fnd = 1; 1873 mlp2 = mlp; 1874 *mlpp = mlp = mlp->ml_next; 1875 free((caddr_t)mlp2); 1876 } else { 1877 mlpp = &mlp->ml_next; 1878 mlp = mlp->ml_next; 1879 } 1880 } 1881 if (fnd) { 1882 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 1883 syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 1884 return; 1885 } 1886 mlp = mlhead; 1887 while (mlp) { 1888 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1889 mlp = mlp->ml_next; 1890 } 1891 fclose(mlfile); 1892 } 1893} 1894 1895void 1896add_mlist(hostp, dirp) 1897 char *hostp, *dirp; 1898{ 1899 struct mountlist *mlp, **mlpp; 1900 FILE *mlfile; 1901 1902 mlpp = &mlhead; 1903 mlp = mlhead; 1904 while (mlp) { 1905 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 1906 return; 1907 mlpp = &mlp->ml_next; 1908 mlp = mlp->ml_next; 1909 } 1910 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1911 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 1912 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 1913 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 1914 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 1915 mlp->ml_next = (struct mountlist *)NULL; 1916 *mlpp = mlp; 1917 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 1918 syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 1919 return; 1920 } 1921 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1922 fclose(mlfile); 1923} 1924 1925/* 1926 * This function is called via. SIGTERM when the system is going down. 1927 * It sends a broadcast RPCMNT_UMNTALL. 1928 */ 1929void 1930send_umntall() 1931{ 1932 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 1933 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 1934 exit(0); 1935} 1936 1937int 1938umntall_each(resultsp, raddr) 1939 caddr_t resultsp; 1940 struct sockaddr_in *raddr; 1941{ 1942 return (1); 1943} 1944 1945/* 1946 * Free up a group list. 1947 */ 1948void 1949free_grp(grp) 1950 struct grouplist *grp; 1951{ 1952 char **addrp; 1953 1954 if (grp->gr_type == GT_HOST) { 1955 if (grp->gr_ptr.gt_hostent->h_name) { 1956 addrp = grp->gr_ptr.gt_hostent->h_addr_list; 1957 while (addrp && *addrp) 1958 free(*addrp++); 1959 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 1960 free(grp->gr_ptr.gt_hostent->h_name); 1961 } 1962 free((caddr_t)grp->gr_ptr.gt_hostent); 1963 } else if (grp->gr_type == GT_NET) { 1964 if (grp->gr_ptr.gt_net.nt_name) 1965 free(grp->gr_ptr.gt_net.nt_name); 1966 } 1967#ifdef ISO 1968 else if (grp->gr_type == GT_ISO) 1969 free((caddr_t)grp->gr_ptr.gt_isoaddr); 1970#endif 1971 free((caddr_t)grp); 1972} 1973 1974#ifdef DEBUG 1975void 1976SYSLOG(int pri, const char *fmt, ...) 1977{ 1978 va_list ap; 1979 1980 va_start(ap, fmt); 1981 vfprintf(stderr, fmt, ap); 1982 va_end(ap); 1983} 1984#endif /* DEBUG */ 1985 1986/* 1987 * Check options for consistency. 1988 */ 1989int 1990check_options(dp) 1991 struct dirlist *dp; 1992{ 1993 1994 if (dp == (struct dirlist *)NULL) 1995 return (1); 1996 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 1997 (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 1998 (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 1999 syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 2000 return (1); 2001 } 2002 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 2003 syslog(LOG_ERR, "-mask requires -net"); 2004 return (1); 2005 } 2006 if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 2007 syslog(LOG_ERR, "-net and -iso mutually exclusive"); 2008 return (1); 2009 } 2010 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 2011 syslog(LOG_ERR, "-alldir has multiple directories"); 2012 return (1); 2013 } 2014 return (0); 2015} 2016 2017/* 2018 * Check an absolute directory path for any symbolic links. Return true 2019 * if no symbolic links are found. 2020 */ 2021int 2022check_dirpath(dirp) 2023 char *dirp; 2024{ 2025 char *cp; 2026 int ret = 1; 2027 struct stat sb; 2028 2029 cp = dirp + 1; 2030 while (*cp && ret) { 2031 if (*cp == '/') { 2032 *cp = '\0'; 2033 if (lstat(dirp, &sb) < 0 || 2034 (sb.st_mode & S_IFMT) != S_IFDIR) 2035 ret = 0; 2036 *cp = '/'; 2037 } 2038 cp++; 2039 } 2040 if (lstat(dirp, &sb) < 0 || 2041 (sb.st_mode & S_IFMT) != S_IFDIR) 2042 ret = 0; 2043 return (ret); 2044} 2045