138460Smckusick /* 261519Sbostic * Copyright (c) 1989, 1993 361519Sbostic * The Regents of the University of California. All rights reserved. 438460Smckusick * 538460Smckusick * This code is derived from software contributed to Berkeley by 651667Smckusick * Herb Hasler and Rick Macklem at The University of Guelph. 738460Smckusick * 842703Sbostic * %sccs.include.redist.c% 938460Smckusick */ 1038460Smckusick 1138460Smckusick #ifndef lint 1261519Sbostic static char copyright[] = 1361519Sbostic "@(#) Copyright (c) 1989, 1993\n\ 1461519Sbostic The Regents of the University of California. All rights reserved.\n"; 1538460Smckusick #endif not lint 1638460Smckusick 1738460Smckusick #ifndef lint 18*65940Sbostic static char sccsid[] = "@(#)mountd.c 8.6 (Berkeley) 01/28/94"; 1938460Smckusick #endif not lint 2038460Smckusick 2138460Smckusick #include <sys/param.h> 2265863Sbostic #include <sys/file.h> 2338460Smckusick #include <sys/ioctl.h> 2438460Smckusick #include <sys/mount.h> 2538460Smckusick #include <sys/socket.h> 2665863Sbostic #include <sys/stat.h> 2752109Smckusick #include <sys/syslog.h> 2865863Sbostic #include <sys/ucred.h> 2965863Sbostic 3038460Smckusick #include <rpc/rpc.h> 3138460Smckusick #include <rpc/pmap_clnt.h> 3238460Smckusick #include <rpc/pmap_prot.h> 3351667Smckusick #ifdef ISO 3451667Smckusick #include <netiso/iso.h> 3551667Smckusick #endif 3638460Smckusick #include <nfs/rpcv2.h> 3738460Smckusick #include <nfs/nfsv2.h> 3865863Sbostic 3965863Sbostic #include <errno.h> 4065863Sbostic #include <grp.h> 4165863Sbostic #include <netdb.h> 4265863Sbostic #include <pwd.h> 4365863Sbostic #include <signal.h> 4453150Smckusick #ifdef DEBUG 4553150Smckusick #include <stdarg.h> 4653150Smckusick #endif 4765863Sbostic #include <stdio.h> 4865863Sbostic #include <stdlib.h> 4965863Sbostic #include <string.h> 5065863Sbostic #include <unistd.h> 5165863Sbostic #include "pathnames.h" 5238460Smckusick 5338460Smckusick /* 5438460Smckusick * Structures for keeping the mount list and export list 5538460Smckusick */ 5638460Smckusick struct mountlist { 5744015Smckusick struct mountlist *ml_next; 5838460Smckusick char ml_host[RPCMNT_NAMELEN+1]; 5938460Smckusick char ml_dirp[RPCMNT_PATHLEN+1]; 6038460Smckusick }; 6138460Smckusick 6251898Smckusick struct dirlist { 6351898Smckusick struct dirlist *dp_left; 6451898Smckusick struct dirlist *dp_right; 6551898Smckusick int dp_flag; 6651898Smckusick struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 6751898Smckusick char dp_dirp[1]; /* Actually malloc'd to size of dir */ 6851898Smckusick }; 6951898Smckusick /* dp_flag bits */ 7051898Smckusick #define DP_DEFSET 0x1 7151898Smckusick 7238460Smckusick struct exportlist { 7338460Smckusick struct exportlist *ex_next; 7451898Smckusick struct dirlist *ex_dirl; 7551898Smckusick struct dirlist *ex_defdir; 7651898Smckusick int ex_flag; 7751898Smckusick fsid_t ex_fs; 7851898Smckusick char *ex_fsdir; 7938460Smckusick }; 8051898Smckusick /* ex_flag bits */ 8152109Smckusick #define EX_LINKED 0x1 8238460Smckusick 8351898Smckusick struct netmsk { 8451898Smckusick u_long nt_net; 8551898Smckusick u_long nt_mask; 8651898Smckusick char *nt_name; 8751898Smckusick }; 8851898Smckusick 8951667Smckusick union grouptypes { 9051667Smckusick struct hostent *gt_hostent; 9151898Smckusick struct netmsk gt_net; 9251667Smckusick #ifdef ISO 9351667Smckusick struct sockaddr_iso *gt_isoaddr; 9451667Smckusick #endif 9551667Smckusick }; 9651667Smckusick 9738460Smckusick struct grouplist { 9851898Smckusick int gr_type; 9951667Smckusick union grouptypes gr_ptr; 10038460Smckusick struct grouplist *gr_next; 10138460Smckusick }; 10251898Smckusick /* Group types */ 10351898Smckusick #define GT_NULL 0x0 10451898Smckusick #define GT_HOST 0x1 10551898Smckusick #define GT_NET 0x2 10651898Smckusick #define GT_ISO 0x4 10738460Smckusick 10851898Smckusick struct hostlist { 10951898Smckusick struct grouplist *ht_grp; 11051898Smckusick struct hostlist *ht_next; 11151667Smckusick }; 11251667Smckusick 11338460Smckusick /* Global defs */ 11446709Sbostic int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist(); 115*65940Sbostic int check_dirpath(); 11651898Smckusick void get_exportlist(), send_umntall(), nextfield(), out_of_mem(); 11751667Smckusick void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp(); 11851898Smckusick void getexp_err(), hang_dirp(), add_dlist(), free_dir(), free_host(); 11953150Smckusick void setnetgrent(), endnetgrent(); 12051898Smckusick struct exportlist *ex_search(), *get_exp(); 12151898Smckusick struct grouplist *get_grp(); 12251898Smckusick char *realpath(), *add_expdir(); 12351898Smckusick struct in_addr inet_makeaddr(); 12451898Smckusick char *inet_ntoa(); 12551898Smckusick struct dirlist *dirp_search(); 12651898Smckusick struct hostlist *get_ht(); 12751667Smckusick #ifdef ISO 12851667Smckusick struct iso_addr *iso_addr(); 12951667Smckusick #endif 13051898Smckusick struct exportlist *exphead; 13144015Smckusick struct mountlist *mlhead; 13251898Smckusick struct grouplist *grphead; 13338460Smckusick char exname[MAXPATHLEN]; 13451667Smckusick struct ucred def_anon = { 13551667Smckusick (u_short) 1, 13651667Smckusick (uid_t) -2, 13751667Smckusick 1, 13851667Smckusick (gid_t) -2, 13951667Smckusick }; 14044015Smckusick int root_only = 1; 14151898Smckusick int opt_flags; 14251898Smckusick /* Bits for above */ 14351898Smckusick #define OP_MAPROOT 0x01 14451898Smckusick #define OP_MAPALL 0x02 14551898Smckusick #define OP_KERB 0x04 14651898Smckusick #define OP_MASK 0x08 14751898Smckusick #define OP_NET 0x10 14851898Smckusick #define OP_ISO 0x20 14951898Smckusick #define OP_ALLDIRS 0x40 15051898Smckusick 15138460Smckusick extern int errno; 15238460Smckusick #ifdef DEBUG 15338460Smckusick int debug = 1; 15451711Smckusick void SYSLOG __P((int, const char *, ...)); 15551711Smckusick #define syslog SYSLOG 15638460Smckusick #else 15738460Smckusick int debug = 0; 15838460Smckusick #endif 15938460Smckusick 16038460Smckusick /* 16138460Smckusick * Mountd server for NFS mount protocol as described in: 16239681Smckusick * NFS: Network File System Protocol Specification, RFC1094, Appendix A 16344015Smckusick * The optional arguments are the exports file name 16439681Smckusick * default: _PATH_EXPORTS 16544015Smckusick * and "-n" to allow nonroot mount. 16638460Smckusick */ 16738460Smckusick main(argc, argv) 16838460Smckusick int argc; 16944015Smckusick char **argv; 17038460Smckusick { 17138460Smckusick SVCXPRT *transp; 17244015Smckusick int c; 17344015Smckusick extern int optind; 17444015Smckusick extern char *optarg; 17538460Smckusick 17644015Smckusick while ((c = getopt(argc, argv, "n")) != EOF) 17744015Smckusick switch (c) { 17844015Smckusick case 'n': 17944015Smckusick root_only = 0; 18044015Smckusick break; 18144015Smckusick default: 18244015Smckusick fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); 18344015Smckusick exit(1); 18444015Smckusick }; 18544015Smckusick argc -= optind; 18644015Smckusick argv += optind; 18751898Smckusick grphead = (struct grouplist *)0; 18851898Smckusick exphead = (struct exportlist *)0; 18944015Smckusick mlhead = (struct mountlist *)0; 19044015Smckusick if (argc == 1) { 19144015Smckusick strncpy(exname, *argv, MAXPATHLEN-1); 19244015Smckusick exname[MAXPATHLEN-1] = '\0'; 19344015Smckusick } else 19444015Smckusick strcpy(exname, _PATH_EXPORTS); 19544338Smckusick openlog("mountd:", LOG_PID, LOG_DAEMON); 19651667Smckusick if (debug) 19751667Smckusick fprintf(stderr,"Getting export list.\n"); 19844015Smckusick get_exportlist(); 19951667Smckusick if (debug) 20051667Smckusick fprintf(stderr,"Getting mount list.\n"); 20144015Smckusick get_mountlist(); 20251667Smckusick if (debug) 20351667Smckusick fprintf(stderr,"Here we go.\n"); 20438460Smckusick if (debug == 0) { 20544690Skarels daemon(0, 0); 20638460Smckusick signal(SIGINT, SIG_IGN); 20738460Smckusick signal(SIGQUIT, SIG_IGN); 20838460Smckusick } 20938460Smckusick signal(SIGHUP, get_exportlist); 21044015Smckusick signal(SIGTERM, send_umntall); 21140494Smckusick { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 21240494Smckusick if (pidfile != NULL) { 21340494Smckusick fprintf(pidfile, "%d\n", getpid()); 21440494Smckusick fclose(pidfile); 21540494Smckusick } 21640494Smckusick } 21738460Smckusick if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { 21838460Smckusick syslog(LOG_ERR, "Can't create socket"); 21938460Smckusick exit(1); 22038460Smckusick } 22138460Smckusick pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 22251667Smckusick if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 22351667Smckusick IPPROTO_UDP)) { 22438460Smckusick syslog(LOG_ERR, "Can't register mount"); 22538460Smckusick exit(1); 22638460Smckusick } 22738460Smckusick svc_run(); 22838460Smckusick syslog(LOG_ERR, "Mountd died"); 22944690Skarels exit(1); 23038460Smckusick } 23138460Smckusick 23238460Smckusick /* 23338460Smckusick * The mount rpc service 23438460Smckusick */ 23538460Smckusick mntsrv(rqstp, transp) 23638460Smckusick register struct svc_req *rqstp; 23738460Smckusick register SVCXPRT *transp; 23838460Smckusick { 23938460Smckusick register struct exportlist *ep; 24051898Smckusick register struct dirlist *dp; 24138460Smckusick nfsv2fh_t nfh; 24238460Smckusick struct authunix_parms *ucr; 24338460Smckusick struct stat stb; 24451898Smckusick struct statfs fsb; 24538460Smckusick struct hostent *hp; 24639681Smckusick u_long saddr; 24751667Smckusick char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; 24851898Smckusick int bad = ENOENT, omask, defset; 24939681Smckusick uid_t uid = -2; 25038460Smckusick 25138460Smckusick /* Get authorization */ 25238460Smckusick switch (rqstp->rq_cred.oa_flavor) { 25338460Smckusick case AUTH_UNIX: 25438460Smckusick ucr = (struct authunix_parms *)rqstp->rq_clntcred; 25539681Smckusick uid = ucr->aup_uid; 25639681Smckusick break; 25738460Smckusick case AUTH_NULL: 25838460Smckusick default: 25939681Smckusick break; 26038460Smckusick } 26138460Smckusick 26239681Smckusick saddr = transp->xp_raddr.sin_addr.s_addr; 26339681Smckusick hp = (struct hostent *)0; 26438460Smckusick switch (rqstp->rq_proc) { 26539681Smckusick case NULLPROC: 26639681Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 26739681Smckusick syslog(LOG_ERR, "Can't send reply"); 26839681Smckusick return; 26938460Smckusick case RPCMNT_MOUNT: 27051667Smckusick if ((uid != 0 && root_only) || uid == -2) { 27139681Smckusick svcerr_weakauth(transp); 27239681Smckusick return; 27339681Smckusick } 27451667Smckusick if (!svc_getargs(transp, xdr_dir, rpcpath)) { 27538460Smckusick svcerr_decode(transp); 27638460Smckusick return; 27738460Smckusick } 27838460Smckusick 27951667Smckusick /* 28051667Smckusick * Get the real pathname and make sure it is a directory 28151667Smckusick * that exists. 28251667Smckusick */ 28351898Smckusick if (realpath(rpcpath, dirpath) == 0 || 28451898Smckusick stat(dirpath, &stb) < 0 || 28551898Smckusick (stb.st_mode & S_IFMT) != S_IFDIR || 28651898Smckusick statfs(dirpath, &fsb) < 0) { 28751667Smckusick chdir("/"); /* Just in case realpath doesn't */ 28851667Smckusick if (debug) 28951898Smckusick fprintf(stderr, "stat failed on %s\n", dirpath); 29038460Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 29138460Smckusick syslog(LOG_ERR, "Can't send reply"); 29238460Smckusick return; 29338460Smckusick } 29438460Smckusick 29538460Smckusick /* Check in the exports list */ 29638460Smckusick omask = sigblock(sigmask(SIGHUP)); 29751898Smckusick ep = ex_search(&fsb.f_fsid); 29851898Smckusick defset = 0; 29951898Smckusick if (ep && (chk_host(ep->ex_defdir, saddr, &defset) || 30051898Smckusick ((dp = dirp_search(ep->ex_dirl, dirpath)) && 30151898Smckusick chk_host(dp, saddr, &defset)) || 30251898Smckusick (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 30351898Smckusick scan_tree(ep->ex_dirl, saddr) == 0))) { 30451667Smckusick /* Get the file handle */ 30551667Smckusick bzero((caddr_t)&nfh, sizeof(nfh)); 30651667Smckusick if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { 30751667Smckusick bad = errno; 30851898Smckusick syslog(LOG_ERR, "Can't get fh for %s", dirpath); 30951667Smckusick if (!svc_sendreply(transp, xdr_long, 31051667Smckusick (caddr_t)&bad)) 31151667Smckusick syslog(LOG_ERR, "Can't send reply"); 31251667Smckusick sigsetmask(omask); 31351667Smckusick return; 31451667Smckusick } 31551667Smckusick if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) 31638460Smckusick syslog(LOG_ERR, "Can't send reply"); 31751667Smckusick if (hp == NULL) 31851667Smckusick hp = gethostbyaddr((caddr_t)&saddr, 31951667Smckusick sizeof(saddr), AF_INET); 32051667Smckusick if (hp) 32151667Smckusick add_mlist(hp->h_name, dirpath); 32251667Smckusick else 32351667Smckusick add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 32451667Smckusick dirpath); 32551667Smckusick if (debug) 32651667Smckusick fprintf(stderr,"Mount successfull.\n"); 32751898Smckusick } else { 32851898Smckusick bad = EACCES; 32951898Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 33051898Smckusick syslog(LOG_ERR, "Can't send reply"); 33138460Smckusick } 33251667Smckusick sigsetmask(omask); 33338460Smckusick return; 33438460Smckusick case RPCMNT_DUMP: 33538460Smckusick if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0)) 33638460Smckusick syslog(LOG_ERR, "Can't send reply"); 33738460Smckusick return; 33838460Smckusick case RPCMNT_UMOUNT: 33951667Smckusick if ((uid != 0 && root_only) || uid == -2) { 34039681Smckusick svcerr_weakauth(transp); 34139681Smckusick return; 34239681Smckusick } 34338460Smckusick if (!svc_getargs(transp, xdr_dir, dirpath)) { 34438460Smckusick svcerr_decode(transp); 34538460Smckusick return; 34638460Smckusick } 34738460Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 34838460Smckusick syslog(LOG_ERR, "Can't send reply"); 34944015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 35044015Smckusick if (hp) 35144015Smckusick del_mlist(hp->h_name, dirpath); 35251667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 35338460Smckusick return; 35438460Smckusick case RPCMNT_UMNTALL: 35551667Smckusick if ((uid != 0 && root_only) || uid == -2) { 35639681Smckusick svcerr_weakauth(transp); 35739681Smckusick return; 35839681Smckusick } 35938460Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 36038460Smckusick syslog(LOG_ERR, "Can't send reply"); 36144015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 36244015Smckusick if (hp) 36344015Smckusick del_mlist(hp->h_name, (char *)0); 36451667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)0); 36538460Smckusick return; 36638460Smckusick case RPCMNT_EXPORT: 36738460Smckusick if (!svc_sendreply(transp, xdr_explist, (caddr_t)0)) 36838460Smckusick syslog(LOG_ERR, "Can't send reply"); 36938460Smckusick return; 37038460Smckusick default: 37138460Smckusick svcerr_noproc(transp); 37238460Smckusick return; 37338460Smckusick } 37438460Smckusick } 37538460Smckusick 37638460Smckusick /* 37738460Smckusick * Xdr conversion for a dirpath string 37838460Smckusick */ 37938460Smckusick xdr_dir(xdrsp, dirp) 38038460Smckusick XDR *xdrsp; 38138460Smckusick char *dirp; 38238460Smckusick { 38338460Smckusick return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 38438460Smckusick } 38538460Smckusick 38638460Smckusick /* 38738460Smckusick * Xdr routine to generate fhstatus 38838460Smckusick */ 38938460Smckusick xdr_fhs(xdrsp, nfh) 39038460Smckusick XDR *xdrsp; 39138460Smckusick nfsv2fh_t *nfh; 39238460Smckusick { 39338460Smckusick int ok = 0; 39438460Smckusick 39538460Smckusick if (!xdr_long(xdrsp, &ok)) 39638460Smckusick return (0); 39738460Smckusick return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); 39838460Smckusick } 39938460Smckusick 40038460Smckusick xdr_mlist(xdrsp, cp) 40138460Smckusick XDR *xdrsp; 40238460Smckusick caddr_t cp; 40338460Smckusick { 40444015Smckusick register struct mountlist *mlp; 40538460Smckusick int true = 1; 40638460Smckusick int false = 0; 40738460Smckusick char *strp; 40838460Smckusick 40944015Smckusick mlp = mlhead; 41044015Smckusick while (mlp) { 41144015Smckusick if (!xdr_bool(xdrsp, &true)) 41244015Smckusick return (0); 41344015Smckusick strp = &mlp->ml_host[0]; 41444015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 41544015Smckusick return (0); 41644015Smckusick strp = &mlp->ml_dirp[0]; 41744015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 41844015Smckusick return (0); 41944015Smckusick mlp = mlp->ml_next; 42038460Smckusick } 42138460Smckusick if (!xdr_bool(xdrsp, &false)) 42238460Smckusick return (0); 42338460Smckusick return (1); 42438460Smckusick } 42538460Smckusick 42638460Smckusick /* 42738460Smckusick * Xdr conversion for export list 42838460Smckusick */ 42938460Smckusick xdr_explist(xdrsp, cp) 43038460Smckusick XDR *xdrsp; 43138460Smckusick caddr_t cp; 43238460Smckusick { 43338460Smckusick register struct exportlist *ep; 43438460Smckusick int false = 0; 43564903Smckusick int omask, putdef; 43638460Smckusick 43738460Smckusick omask = sigblock(sigmask(SIGHUP)); 43851898Smckusick ep = exphead; 43951898Smckusick while (ep) { 44064903Smckusick putdef = 0; 44164903Smckusick if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 44238460Smckusick goto errout; 44364903Smckusick if (ep->ex_defdir && putdef == 0 && 44464903Smckusick put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)0, 44564903Smckusick &putdef)) 44664903Smckusick goto errout; 44738460Smckusick ep = ep->ex_next; 44838460Smckusick } 44938460Smckusick sigsetmask(omask); 45038460Smckusick if (!xdr_bool(xdrsp, &false)) 45138460Smckusick return (0); 45238460Smckusick return (1); 45338460Smckusick errout: 45438460Smckusick sigsetmask(omask); 45538460Smckusick return (0); 45638460Smckusick } 45738460Smckusick 45851898Smckusick /* 45951898Smckusick * Called from xdr_explist() to traverse the tree and export the 46051898Smckusick * directory paths. 46151898Smckusick */ 46264903Smckusick put_exlist(dp, xdrsp, adp, putdefp) 46351898Smckusick register struct dirlist *dp; 46451898Smckusick XDR *xdrsp; 46551898Smckusick struct dirlist *adp; 46664903Smckusick int *putdefp; 46751898Smckusick { 46851898Smckusick register struct grouplist *grp; 46951898Smckusick register struct hostlist *hp; 47051898Smckusick struct in_addr inaddr; 47151898Smckusick int true = 1; 47251898Smckusick int false = 0; 47351898Smckusick int gotalldir = 0; 47451898Smckusick char *strp; 47551898Smckusick 47651898Smckusick if (dp) { 47764903Smckusick if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 47851898Smckusick return (1); 47951898Smckusick if (!xdr_bool(xdrsp, &true)) 48051898Smckusick return (1); 48151898Smckusick strp = dp->dp_dirp; 48251898Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 48351898Smckusick return (1); 48464903Smckusick if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 48551898Smckusick gotalldir = 1; 48664903Smckusick *putdefp = 1; 48764903Smckusick } 48851898Smckusick if ((dp->dp_flag & DP_DEFSET) == 0 && 48951898Smckusick (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 49051898Smckusick hp = dp->dp_hosts; 49151898Smckusick while (hp) { 49251898Smckusick grp = hp->ht_grp; 49351898Smckusick if (grp->gr_type == GT_HOST) { 49451898Smckusick if (!xdr_bool(xdrsp, &true)) 49551898Smckusick return (1); 49651898Smckusick strp = grp->gr_ptr.gt_hostent->h_name; 49751898Smckusick if (!xdr_string(xdrsp, &strp, 49851898Smckusick RPCMNT_NAMELEN)) 49951898Smckusick return (1); 50051898Smckusick } else if (grp->gr_type == GT_NET) { 50151898Smckusick if (!xdr_bool(xdrsp, &true)) 50251898Smckusick return (1); 50351898Smckusick strp = grp->gr_ptr.gt_net.nt_name; 50451898Smckusick if (!xdr_string(xdrsp, &strp, 50551898Smckusick RPCMNT_NAMELEN)) 50651898Smckusick return (1); 50751898Smckusick } 50851898Smckusick hp = hp->ht_next; 50951898Smckusick if (gotalldir && hp == (struct hostlist *)0) { 51051898Smckusick hp = adp->dp_hosts; 51151898Smckusick gotalldir = 0; 51251898Smckusick } 51351898Smckusick } 51451898Smckusick } 51551898Smckusick if (!xdr_bool(xdrsp, &false)) 51651898Smckusick return (1); 51764903Smckusick if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 51851898Smckusick return (1); 51951898Smckusick } 52051898Smckusick return (0); 52151898Smckusick } 52251898Smckusick 52338460Smckusick #define LINESIZ 10240 52438460Smckusick char line[LINESIZ]; 52551898Smckusick FILE *exp_file; 52638460Smckusick 52738460Smckusick /* 52838460Smckusick * Get the export list 52938460Smckusick */ 53046709Sbostic void 53138460Smckusick get_exportlist() 53238460Smckusick { 53338460Smckusick register struct exportlist *ep, *ep2; 53451898Smckusick register struct grouplist *grp, *tgrp; 53551898Smckusick struct exportlist **epp; 53651898Smckusick struct dirlist *dirhead; 53752109Smckusick struct statfs fsb, *fsp; 53851898Smckusick struct hostent *hpe; 53951898Smckusick struct ucred anon; 54053150Smckusick char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 54153150Smckusick int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 54238460Smckusick 54338460Smckusick /* 54438460Smckusick * First, get rid of the old list 54538460Smckusick */ 54651898Smckusick ep = exphead; 54751898Smckusick while (ep) { 54838460Smckusick ep2 = ep; 54938460Smckusick ep = ep->ex_next; 55044015Smckusick free_exp(ep2); 55138460Smckusick } 55251898Smckusick exphead = (struct exportlist *)0; 55338460Smckusick 55451898Smckusick grp = grphead; 55551898Smckusick while (grp) { 55651898Smckusick tgrp = grp; 55751898Smckusick grp = grp->gr_next; 55851898Smckusick free_grp(tgrp); 55951667Smckusick } 56051898Smckusick grphead = (struct grouplist *)0; 56151667Smckusick 56238460Smckusick /* 56352109Smckusick * And delete exports that are in the kernel for all local 56452109Smckusick * file systems. 56552109Smckusick * XXX: Should know how to handle all local exportable file systems 56652109Smckusick * instead of just MOUNT_UFS. 56752109Smckusick */ 56853214Smckusick num = getmntinfo(&fsp, MNT_NOWAIT); 56952109Smckusick for (i = 0; i < num; i++) { 57065713Shibler union { 57165713Shibler struct ufs_args ua; 57265713Shibler struct iso_args ia; 57365713Shibler struct mfs_args ma; 57465713Shibler } targs; 57565713Shibler 57665713Shibler switch (fsp->f_type) { 57765863Sbostic case MOUNT_MFS: 57865713Shibler case MOUNT_UFS: 57965863Sbostic case MOUNT_CD9660: 58065863Sbostic targs.ua.fspec = NULL; 58165713Shibler targs.ua.export.ex_flags = MNT_DELEXPORT; 58252109Smckusick if (mount(fsp->f_type, fsp->f_mntonname, 58365713Shibler fsp->f_flags | MNT_UPDATE, 58465713Shibler (caddr_t)&targs) < 0) 58565713Shibler syslog(LOG_ERR, "Can't delete exports for %s", 58652109Smckusick fsp->f_mntonname); 58752109Smckusick } 58852109Smckusick fsp++; 58952109Smckusick } 59052109Smckusick 59152109Smckusick /* 59238460Smckusick * Read in the exports file and build the list, calling 59351667Smckusick * mount() as we go along to push the export rules into the kernel. 59438460Smckusick */ 59551898Smckusick if ((exp_file = fopen(exname, "r")) == NULL) { 59638460Smckusick syslog(LOG_ERR, "Can't open %s", exname); 59738460Smckusick exit(2); 59838460Smckusick } 59951898Smckusick dirhead = (struct dirlist *)0; 60051898Smckusick while (get_line()) { 60151667Smckusick if (debug) 60251667Smckusick fprintf(stderr,"Got line %s\n",line); 60338460Smckusick cp = line; 60438460Smckusick nextfield(&cp, &endcp); 60551667Smckusick if (*cp == '#') 60651667Smckusick goto nextline; 60751898Smckusick 60851898Smckusick /* 60951898Smckusick * Set defaults. 61051898Smckusick */ 61151898Smckusick has_host = FALSE; 61251898Smckusick anon = def_anon; 61351667Smckusick exflags = MNT_EXPORTED; 61451898Smckusick got_nondir = 0; 61551898Smckusick opt_flags = 0; 61651898Smckusick ep = (struct exportlist *)0; 61744015Smckusick 61844015Smckusick /* 61944015Smckusick * Create new exports list entry 62044015Smckusick */ 62138460Smckusick len = endcp-cp; 62253150Smckusick tgrp = grp = get_grp(); 62351898Smckusick while (len > 0) { 62451898Smckusick if (len > RPCMNT_NAMELEN) { 62553150Smckusick getexp_err(ep, tgrp); 62651898Smckusick goto nextline; 62751667Smckusick } 62845271Smckusick if (*cp == '-') { 62951898Smckusick if (ep == (struct exportlist *)0) { 63053150Smckusick getexp_err(ep, tgrp); 63151898Smckusick goto nextline; 63251898Smckusick } 63351898Smckusick if (debug) 63451898Smckusick fprintf(stderr, "doing opt %s\n", cp); 63551898Smckusick got_nondir = 1; 63651898Smckusick if (do_opt(&cp, &endcp, ep, grp, &has_host, 63751898Smckusick &exflags, &anon)) { 63853150Smckusick getexp_err(ep, tgrp); 63951898Smckusick goto nextline; 64051898Smckusick } 64151898Smckusick } else if (*cp == '/') { 64251898Smckusick savedc = *endcp; 64351898Smckusick *endcp = '\0'; 644*65940Sbostic if (check_dirpath(cp) && 64551898Smckusick statfs(cp, &fsb) >= 0) { 64651898Smckusick if (got_nondir) { 64751898Smckusick syslog(LOG_ERR, "Dirs must be first"); 64853150Smckusick getexp_err(ep, tgrp); 64951898Smckusick goto nextline; 65051898Smckusick } 65151898Smckusick if (ep) { 65251898Smckusick if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 65351898Smckusick ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 65453150Smckusick getexp_err(ep, tgrp); 65551898Smckusick goto nextline; 65651898Smckusick } 65751667Smckusick } else { 65851898Smckusick /* 65951898Smckusick * See if this directory is already 66051898Smckusick * in the list. 66151898Smckusick */ 66251898Smckusick ep = ex_search(&fsb.f_fsid); 66351898Smckusick if (ep == (struct exportlist *)0) { 66451898Smckusick ep = get_exp(); 66551898Smckusick ep->ex_fs = fsb.f_fsid; 66651898Smckusick ep->ex_fsdir = (char *) 66751898Smckusick malloc(strlen(fsb.f_mntonname) + 1); 66851898Smckusick if (ep->ex_fsdir) 66951898Smckusick strcpy(ep->ex_fsdir, 67051898Smckusick fsb.f_mntonname); 67151898Smckusick else 67251898Smckusick out_of_mem(); 67351898Smckusick if (debug) 67451898Smckusick fprintf(stderr, 67551898Smckusick "Making new ep fs=0x%x,0x%x\n", 67651898Smckusick fsb.f_fsid.val[0], 67751898Smckusick fsb.f_fsid.val[1]); 67851898Smckusick } else if (debug) 67951898Smckusick fprintf(stderr, 68051898Smckusick "Found ep fs=0x%x,0x%x\n", 68151898Smckusick fsb.f_fsid.val[0], 68251898Smckusick fsb.f_fsid.val[1]); 68338460Smckusick } 68451898Smckusick 68551898Smckusick /* 68651898Smckusick * Add dirpath to export mount point. 68751898Smckusick */ 68851898Smckusick dirp = add_expdir(&dirhead, cp, len); 68951898Smckusick dirplen = len; 69051898Smckusick } else { 69153150Smckusick getexp_err(ep, tgrp); 69251898Smckusick goto nextline; 69351898Smckusick } 69451898Smckusick *endcp = savedc; 69551898Smckusick } else { 69651898Smckusick savedc = *endcp; 69751898Smckusick *endcp = '\0'; 69851898Smckusick got_nondir = 1; 69953150Smckusick if (ep == (struct exportlist *)0) { 70053150Smckusick getexp_err(ep, tgrp); 70151898Smckusick goto nextline; 70251898Smckusick } 70353150Smckusick 70453150Smckusick /* 70553150Smckusick * Get the host or netgroup. 70653150Smckusick */ 70753150Smckusick setnetgrent(cp); 70853150Smckusick netgrp = getnetgrent(&hst, &usr, &dom); 70953150Smckusick do { 71053150Smckusick if (has_host) { 71153150Smckusick grp->gr_next = get_grp(); 71253150Smckusick grp = grp->gr_next; 71353150Smckusick } 71453150Smckusick if (netgrp) { 71553150Smckusick if (get_host(hst, grp)) { 71653150Smckusick syslog(LOG_ERR, "Bad netgroup %s", cp); 71753150Smckusick getexp_err(ep, tgrp); 71853150Smckusick goto nextline; 71953150Smckusick } 72053150Smckusick } else if (get_host(cp, grp)) { 72153150Smckusick getexp_err(ep, tgrp); 72253150Smckusick goto nextline; 72353150Smckusick } 72453150Smckusick has_host = TRUE; 72553150Smckusick } while (netgrp && getnetgrent(&hst, &usr, &dom)); 72653150Smckusick endnetgrent(); 72751898Smckusick *endcp = savedc; 72838460Smckusick } 72938460Smckusick cp = endcp; 73038460Smckusick nextfield(&cp, &endcp); 73145271Smckusick len = endcp - cp; 73238460Smckusick } 73351898Smckusick if (check_options(dirhead)) { 73453150Smckusick getexp_err(ep, tgrp); 73551898Smckusick goto nextline; 73651898Smckusick } 73751898Smckusick if (!has_host) { 73851898Smckusick grp->gr_type = GT_HOST; 73951667Smckusick if (debug) 74051667Smckusick fprintf(stderr,"Adding a default entry\n"); 74151667Smckusick /* add a default group and make the grp list NULL */ 74251667Smckusick hpe = (struct hostent *)malloc(sizeof(struct hostent)); 74351898Smckusick if (hpe == (struct hostent *)0) 74451898Smckusick out_of_mem(); 74551898Smckusick hpe->h_name = "Default"; 74651667Smckusick hpe->h_addrtype = AF_INET; 74751667Smckusick hpe->h_length = sizeof (u_long); 74851712Smckusick hpe->h_addr_list = (char **)0; 74951898Smckusick grp->gr_ptr.gt_hostent = hpe; 75053150Smckusick 75153150Smckusick /* 75253150Smckusick * Don't allow a network export coincide with a list of 75353150Smckusick * host(s) on the same line. 75453150Smckusick */ 75553150Smckusick } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 75653150Smckusick getexp_err(ep, tgrp); 75753150Smckusick goto nextline; 75851667Smckusick } 75953150Smckusick 76053150Smckusick /* 76153150Smckusick * Loop through hosts, pushing the exports into the kernel. 76253150Smckusick * After loop, tgrp points to the start of the list and 76353150Smckusick * grp points to the last entry in the list. 76453150Smckusick */ 76553150Smckusick grp = tgrp; 76653150Smckusick do { 76753150Smckusick if (do_mount(ep, grp, exflags, &anon, dirp, 76851898Smckusick dirplen, &fsb)) { 76953150Smckusick getexp_err(ep, tgrp); 77051898Smckusick goto nextline; 77153150Smckusick } 77253150Smckusick } while (grp->gr_next && (grp = grp->gr_next)); 77351898Smckusick 77451898Smckusick /* 77551898Smckusick * Success. Update the data structures. 77651898Smckusick */ 77751898Smckusick if (has_host) { 77853150Smckusick hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS)); 77951898Smckusick grp->gr_next = grphead; 78053150Smckusick grphead = tgrp; 78151898Smckusick } else { 78251898Smckusick hang_dirp(dirhead, (struct grouplist *)0, ep, 78353150Smckusick (opt_flags & OP_ALLDIRS)); 78451898Smckusick free_grp(grp); 78551898Smckusick } 78651898Smckusick dirhead = (struct dirlist *)0; 78751898Smckusick if ((ep->ex_flag & EX_LINKED) == 0) { 78851898Smckusick ep2 = exphead; 78951898Smckusick epp = &exphead; 79051898Smckusick 79151898Smckusick /* 79251898Smckusick * Insert in the list in alphabetical order. 79351898Smckusick */ 79451898Smckusick while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 79551898Smckusick epp = &ep2->ex_next; 79651898Smckusick ep2 = ep2->ex_next; 79751898Smckusick } 79851898Smckusick if (ep2) 79951898Smckusick ep->ex_next = ep2; 80051898Smckusick *epp = ep; 80151898Smckusick ep->ex_flag |= EX_LINKED; 80251898Smckusick } 80351898Smckusick nextline: 80451898Smckusick if (dirhead) { 80551898Smckusick free_dir(dirhead); 80651898Smckusick dirhead = (struct dirlist *)0; 80751898Smckusick } 80851898Smckusick } 80951898Smckusick fclose(exp_file); 81051898Smckusick } 81151898Smckusick 81251898Smckusick /* 81351898Smckusick * Allocate an export list element 81451898Smckusick */ 81551898Smckusick struct exportlist * 81651898Smckusick get_exp() 81751898Smckusick { 81851898Smckusick register struct exportlist *ep; 81951898Smckusick 82051898Smckusick ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 82151898Smckusick if (ep == (struct exportlist *)0) 82251898Smckusick out_of_mem(); 82351898Smckusick bzero((caddr_t)ep, sizeof (struct exportlist)); 82451898Smckusick return (ep); 82551898Smckusick } 82651898Smckusick 82751898Smckusick /* 82851898Smckusick * Allocate a group list element 82951898Smckusick */ 83051898Smckusick struct grouplist * 83151898Smckusick get_grp() 83251898Smckusick { 83351898Smckusick register struct grouplist *gp; 83451898Smckusick 83551898Smckusick gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 83651898Smckusick if (gp == (struct grouplist *)0) 83751898Smckusick out_of_mem(); 83851898Smckusick bzero((caddr_t)gp, sizeof (struct grouplist)); 83951898Smckusick return (gp); 84051898Smckusick } 84151898Smckusick 84251898Smckusick /* 84351898Smckusick * Clean up upon an error in get_exportlist(). 84451898Smckusick */ 84551898Smckusick void 84651898Smckusick getexp_err(ep, grp) 84751898Smckusick struct exportlist *ep; 84851898Smckusick struct grouplist *grp; 84951898Smckusick { 85053150Smckusick struct grouplist *tgrp; 85151898Smckusick 85251898Smckusick syslog(LOG_ERR, "Bad exports list line %s", line); 85359017Smckusick if (ep && (ep->ex_flag & EX_LINKED) == 0) 85451898Smckusick free_exp(ep); 85553150Smckusick while (grp) { 85653150Smckusick tgrp = grp; 85753150Smckusick grp = grp->gr_next; 85853150Smckusick free_grp(tgrp); 85953150Smckusick } 86051898Smckusick } 86151898Smckusick 86251898Smckusick /* 86351898Smckusick * Search the export list for a matching fs. 86451898Smckusick */ 86551898Smckusick struct exportlist * 86651898Smckusick ex_search(fsid) 86752109Smckusick fsid_t *fsid; 86851898Smckusick { 86951898Smckusick register struct exportlist *ep; 87051898Smckusick 87151898Smckusick ep = exphead; 87251898Smckusick while (ep) { 87351898Smckusick if (ep->ex_fs.val[0] == fsid->val[0] && 87451898Smckusick ep->ex_fs.val[1] == fsid->val[1]) 87551898Smckusick return (ep); 87651898Smckusick ep = ep->ex_next; 87751898Smckusick } 87851898Smckusick return (ep); 87951898Smckusick } 88051898Smckusick 88151898Smckusick /* 88251898Smckusick * Add a directory path to the list. 88351898Smckusick */ 88451898Smckusick char * 88551898Smckusick add_expdir(dpp, cp, len) 88651898Smckusick struct dirlist **dpp; 88751898Smckusick char *cp; 88851898Smckusick int len; 88951898Smckusick { 89051898Smckusick register struct dirlist *dp; 89151898Smckusick 89251898Smckusick dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 89351898Smckusick dp->dp_left = *dpp; 89451898Smckusick dp->dp_right = (struct dirlist *)0; 89551898Smckusick dp->dp_flag = 0; 89651898Smckusick dp->dp_hosts = (struct hostlist *)0; 89751898Smckusick strcpy(dp->dp_dirp, cp); 89851898Smckusick *dpp = dp; 89951898Smckusick return (dp->dp_dirp); 90051898Smckusick } 90151898Smckusick 90251898Smckusick /* 90351898Smckusick * Hang the dir list element off the dirpath binary tree as required 90451898Smckusick * and update the entry for host. 90551898Smckusick */ 90651898Smckusick void 90751898Smckusick hang_dirp(dp, grp, ep, alldirs) 90851898Smckusick register struct dirlist *dp; 90951898Smckusick struct grouplist *grp; 91051898Smckusick struct exportlist *ep; 91151898Smckusick int alldirs; 91251898Smckusick { 91351898Smckusick register struct hostlist *hp; 91451898Smckusick struct dirlist *dp2; 91551898Smckusick 91651898Smckusick if (alldirs) { 91751898Smckusick if (ep->ex_defdir) 91851898Smckusick free((caddr_t)dp); 91951898Smckusick else 92051898Smckusick ep->ex_defdir = dp; 92155292Smckusick if (grp == (struct grouplist *)0) 92255292Smckusick ep->ex_defdir->dp_flag |= DP_DEFSET; 92355292Smckusick else while (grp) { 92451898Smckusick hp = get_ht(); 92551898Smckusick hp->ht_grp = grp; 92651898Smckusick hp->ht_next = ep->ex_defdir->dp_hosts; 92751898Smckusick ep->ex_defdir->dp_hosts = hp; 92855292Smckusick grp = grp->gr_next; 92955292Smckusick } 93051898Smckusick } else { 93153150Smckusick 93253150Smckusick /* 93353150Smckusick * Loop throught the directories adding them to the tree. 93453150Smckusick */ 93551898Smckusick while (dp) { 93651898Smckusick dp2 = dp->dp_left; 93753150Smckusick add_dlist(&ep->ex_dirl, dp, grp); 93851898Smckusick dp = dp2; 93951898Smckusick } 94051898Smckusick } 94151898Smckusick } 94251898Smckusick 94351898Smckusick /* 94451898Smckusick * Traverse the binary tree either updating a node that is already there 94551898Smckusick * for the new directory or adding the new node. 94651898Smckusick */ 94751898Smckusick void 94853150Smckusick add_dlist(dpp, newdp, grp) 94951898Smckusick struct dirlist **dpp; 95051898Smckusick struct dirlist *newdp; 95153150Smckusick register struct grouplist *grp; 95251898Smckusick { 95351898Smckusick register struct dirlist *dp; 95453150Smckusick register struct hostlist *hp; 95551898Smckusick int cmp; 95651898Smckusick 95751898Smckusick dp = *dpp; 95851898Smckusick if (dp) { 95951898Smckusick cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 96051898Smckusick if (cmp > 0) { 96153150Smckusick add_dlist(&dp->dp_left, newdp, grp); 96251898Smckusick return; 96351898Smckusick } else if (cmp < 0) { 96453150Smckusick add_dlist(&dp->dp_right, newdp, grp); 96551898Smckusick return; 96651898Smckusick } else 96751898Smckusick free((caddr_t)newdp); 96851898Smckusick } else { 96951898Smckusick dp = newdp; 97051898Smckusick dp->dp_left = (struct dirlist *)0; 97151898Smckusick *dpp = dp; 97251898Smckusick } 97353150Smckusick if (grp) { 97453150Smckusick 97553150Smckusick /* 97653150Smckusick * Hang all of the host(s) off of the directory point. 97753150Smckusick */ 97853150Smckusick do { 97953150Smckusick hp = get_ht(); 98053150Smckusick hp->ht_grp = grp; 98153150Smckusick hp->ht_next = dp->dp_hosts; 98253150Smckusick dp->dp_hosts = hp; 98353150Smckusick grp = grp->gr_next; 98453150Smckusick } while (grp); 98551898Smckusick } else 98651898Smckusick dp->dp_flag |= DP_DEFSET; 98751898Smckusick } 98851898Smckusick 98951898Smckusick /* 99051898Smckusick * Search for a dirpath on the export point. 99151898Smckusick */ 99251898Smckusick struct dirlist * 99351898Smckusick dirp_search(dp, dirpath) 99451898Smckusick register struct dirlist *dp; 99551898Smckusick char *dirpath; 99651898Smckusick { 99751898Smckusick register int cmp; 99851898Smckusick 99951898Smckusick if (dp) { 100051898Smckusick cmp = strcmp(dp->dp_dirp, dirpath); 100151898Smckusick if (cmp > 0) 100251898Smckusick return (dirp_search(dp->dp_left, dirpath)); 100351898Smckusick else if (cmp < 0) 100451898Smckusick return (dirp_search(dp->dp_right, dirpath)); 100551898Smckusick else 100651898Smckusick return (dp); 100751898Smckusick } 100851898Smckusick return (dp); 100951898Smckusick } 101051898Smckusick 101151898Smckusick /* 101251898Smckusick * Scan for a host match in a directory tree. 101351898Smckusick */ 101451898Smckusick chk_host(dp, saddr, defsetp) 101551898Smckusick struct dirlist *dp; 101651898Smckusick u_long saddr; 101751898Smckusick int *defsetp; 101851898Smckusick { 101951898Smckusick register struct hostlist *hp; 102051898Smckusick register struct grouplist *grp; 102151898Smckusick register u_long **addrp; 102251898Smckusick 102351898Smckusick if (dp) { 102451898Smckusick if (dp->dp_flag & DP_DEFSET) 102551898Smckusick *defsetp = 1; 102651898Smckusick hp = dp->dp_hosts; 102751898Smckusick while (hp) { 102851898Smckusick grp = hp->ht_grp; 102951898Smckusick switch (grp->gr_type) { 103051898Smckusick case GT_HOST: 103151898Smckusick addrp = (u_long **) 103251898Smckusick grp->gr_ptr.gt_hostent->h_addr_list; 103351898Smckusick while (*addrp) { 103451898Smckusick if (**addrp == saddr) 103551898Smckusick return (1); 103651898Smckusick addrp++; 103751898Smckusick } 103851898Smckusick break; 103951898Smckusick case GT_NET: 104051898Smckusick if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 104151898Smckusick grp->gr_ptr.gt_net.nt_net) 104251898Smckusick return (1); 104351898Smckusick break; 104451898Smckusick }; 104551898Smckusick hp = hp->ht_next; 104651898Smckusick } 104751898Smckusick } 104851898Smckusick return (0); 104951898Smckusick } 105051898Smckusick 105151898Smckusick /* 105251898Smckusick * Scan tree for a host that matches the address. 105351898Smckusick */ 105451898Smckusick scan_tree(dp, saddr) 105551898Smckusick register struct dirlist *dp; 105651898Smckusick u_long saddr; 105751898Smckusick { 105851898Smckusick int defset; 105951898Smckusick 106051898Smckusick if (dp) { 106151898Smckusick if (scan_tree(dp->dp_left, saddr)) 106251898Smckusick return (1); 106351898Smckusick if (chk_host(dp, saddr, &defset)) 106451898Smckusick return (1); 106551898Smckusick if (scan_tree(dp->dp_right, saddr)) 106651898Smckusick return (1); 106751898Smckusick } 106851898Smckusick return (0); 106951898Smckusick } 107051898Smckusick 107151898Smckusick /* 107251898Smckusick * Traverse the dirlist tree and free it up. 107351898Smckusick */ 107451898Smckusick void 107551898Smckusick free_dir(dp) 107651898Smckusick register struct dirlist *dp; 107751898Smckusick { 107851898Smckusick 107951898Smckusick if (dp) { 108051898Smckusick free_dir(dp->dp_left); 108151898Smckusick free_dir(dp->dp_right); 108251898Smckusick free_host(dp->dp_hosts); 108351898Smckusick free((caddr_t)dp); 108451898Smckusick } 108551898Smckusick } 108651898Smckusick 108751898Smckusick /* 108851898Smckusick * Parse the option string and update fields. 108951898Smckusick * Option arguments may either be -<option>=<value> or 109051898Smckusick * -<option> <value> 109151898Smckusick */ 109251898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 109351898Smckusick char **cpp, **endcpp; 109451898Smckusick struct exportlist *ep; 109551898Smckusick struct grouplist *grp; 109651898Smckusick int *has_hostp; 109751898Smckusick int *exflagsp; 109851898Smckusick struct ucred *cr; 109951898Smckusick { 110051898Smckusick register char *cpoptarg, *cpoptend; 110151898Smckusick char *cp, *endcp, *cpopt, savedc, savedc2; 110251898Smckusick int allflag, usedarg; 110351898Smckusick 110451898Smckusick cpopt = *cpp; 110551898Smckusick cpopt++; 110651898Smckusick cp = *endcpp; 110751898Smckusick savedc = *cp; 110851898Smckusick *cp = '\0'; 110951898Smckusick while (cpopt && *cpopt) { 111051898Smckusick allflag = 1; 111151898Smckusick usedarg = -2; 111251898Smckusick if (cpoptend = index(cpopt, ',')) { 111351898Smckusick *cpoptend++ = '\0'; 111451898Smckusick if (cpoptarg = index(cpopt, '=')) 111551898Smckusick *cpoptarg++ = '\0'; 111651898Smckusick } else { 111751898Smckusick if (cpoptarg = index(cpopt, '=')) 111851898Smckusick *cpoptarg++ = '\0'; 111951898Smckusick else { 112051898Smckusick *cp = savedc; 112151898Smckusick nextfield(&cp, &endcp); 112251898Smckusick **endcpp = '\0'; 112351898Smckusick if (endcp > cp && *cp != '-') { 112451898Smckusick cpoptarg = cp; 112551898Smckusick savedc2 = *endcp; 112651898Smckusick *endcp = '\0'; 112751898Smckusick usedarg = 0; 112851667Smckusick } 112951667Smckusick } 113051667Smckusick } 113151898Smckusick if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 113251898Smckusick *exflagsp |= MNT_EXRDONLY; 113351898Smckusick } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 113451898Smckusick !(allflag = strcmp(cpopt, "mapall")) || 113551898Smckusick !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 113651898Smckusick usedarg++; 113751898Smckusick parsecred(cpoptarg, cr); 113851898Smckusick if (allflag == 0) { 113951898Smckusick *exflagsp |= MNT_EXPORTANON; 114051898Smckusick opt_flags |= OP_MAPALL; 114151898Smckusick } else 114251898Smckusick opt_flags |= OP_MAPROOT; 114351898Smckusick } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 114451898Smckusick *exflagsp |= MNT_EXKERB; 114551898Smckusick opt_flags |= OP_KERB; 114653150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "mask") || 114753150Smckusick !strcmp(cpopt, "m"))) { 114851898Smckusick if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 114951898Smckusick syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 115051898Smckusick return (1); 115151898Smckusick } 115251898Smckusick usedarg++; 115351898Smckusick opt_flags |= OP_MASK; 115453150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "network") || 115553150Smckusick !strcmp(cpopt, "n"))) { 115651898Smckusick if (grp->gr_type != GT_NULL) { 115751898Smckusick syslog(LOG_ERR, "Network/host conflict"); 115851898Smckusick return (1); 115951898Smckusick } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 116051898Smckusick syslog(LOG_ERR, "Bad net: %s", cpoptarg); 116151898Smckusick return (1); 116251898Smckusick } 116351898Smckusick grp->gr_type = GT_NET; 116451898Smckusick *has_hostp = 1; 116551898Smckusick usedarg++; 116651898Smckusick opt_flags |= OP_NET; 116751898Smckusick } else if (!strcmp(cpopt, "alldirs")) { 116851898Smckusick opt_flags |= OP_ALLDIRS; 116951898Smckusick #ifdef ISO 117051898Smckusick } else if (cpoptarg && !strcmp(cpopt, "iso")) { 117151898Smckusick if (get_isoaddr(cpoptarg, grp)) { 117251898Smckusick syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 117351898Smckusick return (1); 117451898Smckusick } 117551898Smckusick *has_hostp = 1; 117651898Smckusick usedarg++; 117751898Smckusick opt_flags |= OP_ISO; 117851898Smckusick #endif /* ISO */ 117951898Smckusick } else { 118051898Smckusick syslog(LOG_ERR, "Bad opt %s", cpopt); 118151898Smckusick return (1); 118251667Smckusick } 118351898Smckusick if (usedarg >= 0) { 118451898Smckusick *endcp = savedc2; 118551898Smckusick **endcpp = savedc; 118651898Smckusick if (usedarg > 0) { 118751898Smckusick *cpp = cp; 118851898Smckusick *endcpp = endcp; 118951898Smckusick } 119051898Smckusick return (0); 119151898Smckusick } 119251898Smckusick cpopt = cpoptend; 119351667Smckusick } 119451898Smckusick **endcpp = savedc; 119551898Smckusick return (0); 119651898Smckusick } 119751898Smckusick 119851898Smckusick /* 119951898Smckusick * Translate a character string to the corresponding list of network 120051898Smckusick * addresses for a hostname. 120151898Smckusick */ 120251898Smckusick get_host(cp, grp) 120351898Smckusick char *cp; 120451898Smckusick register struct grouplist *grp; 120551898Smckusick { 120651898Smckusick register struct hostent *hp, *nhp; 120751898Smckusick register char **addrp, **naddrp; 120851898Smckusick struct hostent t_host; 120951898Smckusick int i; 121051898Smckusick u_long saddr; 121151898Smckusick char *aptr[2]; 121251898Smckusick 121351898Smckusick if (grp->gr_type != GT_NULL) 121451898Smckusick return (1); 121551898Smckusick if ((hp = gethostbyname(cp)) == NULL) { 121651898Smckusick if (isdigit(*cp)) { 121751898Smckusick saddr = inet_addr(cp); 121851898Smckusick if (saddr == -1) { 121951898Smckusick syslog(LOG_ERR, "Inet_addr failed"); 122051898Smckusick return (1); 122151898Smckusick } 122251898Smckusick if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 122351898Smckusick AF_INET)) == NULL) { 122451898Smckusick hp = &t_host; 122551898Smckusick hp->h_name = cp; 122651898Smckusick hp->h_addrtype = AF_INET; 122751898Smckusick hp->h_length = sizeof (u_long); 122851898Smckusick hp->h_addr_list = aptr; 122951898Smckusick aptr[0] = (char *)&saddr; 123051898Smckusick aptr[1] = (char *)0; 123151898Smckusick } 123251898Smckusick } else { 123351898Smckusick syslog(LOG_ERR, "Gethostbyname failed"); 123451898Smckusick return (1); 123551898Smckusick } 123651898Smckusick } 123751898Smckusick grp->gr_type = GT_HOST; 123851898Smckusick nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 123951898Smckusick malloc(sizeof(struct hostent)); 124051898Smckusick if (nhp == (struct hostent *)0) 124151898Smckusick out_of_mem(); 124251898Smckusick bcopy((caddr_t)hp, (caddr_t)nhp, 124351898Smckusick sizeof(struct hostent)); 124451898Smckusick i = strlen(hp->h_name)+1; 124551898Smckusick nhp->h_name = (char *)malloc(i); 124651898Smckusick if (nhp->h_name == (char *)0) 124751898Smckusick out_of_mem(); 124851898Smckusick bcopy(hp->h_name, nhp->h_name, i); 124951898Smckusick addrp = hp->h_addr_list; 125051898Smckusick i = 1; 125151898Smckusick while (*addrp++) 125251898Smckusick i++; 125351898Smckusick naddrp = nhp->h_addr_list = (char **) 125451898Smckusick malloc(i*sizeof(char *)); 125551898Smckusick if (naddrp == (char **)0) 125651898Smckusick out_of_mem(); 125751898Smckusick addrp = hp->h_addr_list; 125851898Smckusick while (*addrp) { 125951898Smckusick *naddrp = (char *) 126051898Smckusick malloc(hp->h_length); 126151898Smckusick if (*naddrp == (char *)0) 126251898Smckusick out_of_mem(); 126351898Smckusick bcopy(*addrp, *naddrp, 126451898Smckusick hp->h_length); 126551898Smckusick addrp++; 126651898Smckusick naddrp++; 126751898Smckusick } 126851898Smckusick *naddrp = (char *)0; 126953150Smckusick if (debug) 127053150Smckusick fprintf(stderr, "got host %s\n", hp->h_name); 127151898Smckusick return (0); 127251898Smckusick } 127351898Smckusick 127451898Smckusick /* 127551898Smckusick * Free up an exports list component 127651898Smckusick */ 127751898Smckusick void 127851898Smckusick free_exp(ep) 127951898Smckusick register struct exportlist *ep; 128051898Smckusick { 128151898Smckusick 128251898Smckusick if (ep->ex_defdir) { 128351898Smckusick free_host(ep->ex_defdir->dp_hosts); 128451898Smckusick free((caddr_t)ep->ex_defdir); 128551898Smckusick } 128651898Smckusick if (ep->ex_fsdir) 128751898Smckusick free(ep->ex_fsdir); 128851898Smckusick free_dir(ep->ex_dirl); 128951898Smckusick free((caddr_t)ep); 129051898Smckusick } 129151898Smckusick 129251898Smckusick /* 129351898Smckusick * Free hosts. 129451898Smckusick */ 129551898Smckusick void 129651898Smckusick free_host(hp) 129751898Smckusick register struct hostlist *hp; 129851898Smckusick { 129951898Smckusick register struct hostlist *hp2; 130051898Smckusick 130151898Smckusick while (hp) { 130251898Smckusick hp2 = hp; 130351898Smckusick hp = hp->ht_next; 130451898Smckusick free((caddr_t)hp2); 130551898Smckusick } 130651898Smckusick } 130751898Smckusick 130851898Smckusick struct hostlist * 130951898Smckusick get_ht() 131051898Smckusick { 131151898Smckusick register struct hostlist *hp; 131251898Smckusick 131351898Smckusick hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 131451898Smckusick if (hp == (struct hostlist *)0) 131551898Smckusick out_of_mem(); 131651898Smckusick hp->ht_next = (struct hostlist *)0; 131751898Smckusick return (hp); 131851898Smckusick } 131951898Smckusick 132051898Smckusick #ifdef ISO 132151898Smckusick /* 132251898Smckusick * Translate an iso address. 132351898Smckusick */ 132451898Smckusick get_isoaddr(cp, grp) 132551898Smckusick char *cp; 132651898Smckusick struct grouplist *grp; 132751898Smckusick { 132851898Smckusick struct iso_addr *isop; 132951898Smckusick struct sockaddr_iso *isoaddr; 133051898Smckusick 133151898Smckusick if (grp->gr_type != GT_NULL) 133251898Smckusick return (1); 133351898Smckusick if ((isop = iso_addr(cp)) == NULL) { 133451898Smckusick syslog(LOG_ERR, 133551898Smckusick "iso_addr failed, ignored"); 133651898Smckusick return (1); 133751898Smckusick } 133851898Smckusick isoaddr = (struct sockaddr_iso *) 133951898Smckusick malloc(sizeof (struct sockaddr_iso)); 134051898Smckusick if (isoaddr == (struct sockaddr_iso *)0) 134151898Smckusick out_of_mem(); 134251898Smckusick bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 134351898Smckusick bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 134451898Smckusick sizeof (struct iso_addr)); 134551898Smckusick isoaddr->siso_len = sizeof (struct sockaddr_iso); 134651898Smckusick isoaddr->siso_family = AF_ISO; 134751898Smckusick grp->gr_type = GT_ISO; 134851898Smckusick grp->gr_ptr.gt_isoaddr = isoaddr; 134951898Smckusick return (0); 135051898Smckusick } 135151898Smckusick #endif /* ISO */ 135251898Smckusick 135351898Smckusick /* 135451898Smckusick * Out of memory, fatal 135551898Smckusick */ 135651898Smckusick void 135751898Smckusick out_of_mem() 135851898Smckusick { 135951898Smckusick 136051898Smckusick syslog(LOG_ERR, "Out of memory"); 136151667Smckusick exit(2); 136251667Smckusick } 136351667Smckusick 136451898Smckusick /* 136551898Smckusick * Do the mount syscall with the update flag to push the export info into 136651898Smckusick * the kernel. 136751898Smckusick */ 136851898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 136951667Smckusick struct exportlist *ep; 137051667Smckusick struct grouplist *grp; 137151898Smckusick int exflags; 137251667Smckusick struct ucred *anoncrp; 137351898Smckusick char *dirp; 137451898Smckusick int dirplen; 137551898Smckusick struct statfs *fsb; 137651667Smckusick { 137751898Smckusick register char *cp = (char *)0; 137851667Smckusick register u_long **addrp; 137951898Smckusick int done; 138051898Smckusick char savedc; 138151898Smckusick struct sockaddr_in sin, imask; 138265713Shibler union { 138365713Shibler struct ufs_args ua; 138465713Shibler struct iso_args ia; 138565713Shibler struct mfs_args ma; 138665713Shibler } args; 138751898Smckusick u_long net; 138851667Smckusick 138965713Shibler args.ua.fspec = 0; 139065713Shibler args.ua.export.ex_flags = exflags; 139165713Shibler args.ua.export.ex_anon = *anoncrp; 139255878Smckusick bzero((char *)&sin, sizeof(sin)); 139355878Smckusick bzero((char *)&imask, sizeof(imask)); 139451667Smckusick sin.sin_family = AF_INET; 139551667Smckusick sin.sin_len = sizeof(sin); 139651898Smckusick imask.sin_family = AF_INET; 139751898Smckusick imask.sin_len = sizeof(sin); 139851898Smckusick if (grp->gr_type == GT_HOST) 139951667Smckusick addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 140051898Smckusick else 140151898Smckusick addrp = (u_long **)0; 140251667Smckusick done = FALSE; 140351898Smckusick while (!done) { 140451898Smckusick switch (grp->gr_type) { 140551898Smckusick case GT_HOST: 140664903Smckusick if (addrp) { 140751712Smckusick sin.sin_addr.s_addr = **addrp; 140865713Shibler args.ua.export.ex_addrlen = sizeof(sin); 140964903Smckusick } else 141065713Shibler args.ua.export.ex_addrlen = 0; 141165713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 141265713Shibler args.ua.export.ex_masklen = 0; 141351898Smckusick break; 141451898Smckusick case GT_NET: 141551898Smckusick if (grp->gr_ptr.gt_net.nt_mask) 141651898Smckusick imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 141751898Smckusick else { 141851898Smckusick net = ntohl(grp->gr_ptr.gt_net.nt_net); 141951898Smckusick if (IN_CLASSA(net)) 142051898Smckusick imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 142151898Smckusick else if (IN_CLASSB(net)) 142251898Smckusick imask.sin_addr.s_addr = 142351898Smckusick inet_addr("255.255.0.0"); 142451898Smckusick else 142551898Smckusick imask.sin_addr.s_addr = 142651898Smckusick inet_addr("255.255.255.0"); 142751898Smckusick grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 142851898Smckusick } 142951898Smckusick sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 143065713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 143165713Shibler args.ua.export.ex_addrlen = sizeof (sin); 143265713Shibler args.ua.export.ex_mask = (struct sockaddr *)&imask; 143365713Shibler args.ua.export.ex_masklen = sizeof (imask); 143451898Smckusick break; 143551667Smckusick #ifdef ISO 143651898Smckusick case GT_ISO: 143765713Shibler args.ua.export.ex_addr = 143865713Shibler (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 143965713Shibler args.ua.export.ex_addrlen = 144065713Shibler sizeof(struct sockaddr_iso); 144165713Shibler args.ua.export.ex_masklen = 0; 144251898Smckusick break; 144351667Smckusick #endif /* ISO */ 144451898Smckusick default: 144551667Smckusick syslog(LOG_ERR, "Bad grouptype"); 144651898Smckusick if (cp) 144751898Smckusick *cp = savedc; 144851898Smckusick return (1); 144951898Smckusick }; 145052109Smckusick 145152109Smckusick /* 145252109Smckusick * XXX: 145352109Smckusick * Maybe I should just use the fsb->f_mntonname path instead 145452109Smckusick * of looping back up the dirp to the mount point?? 145552109Smckusick * Also, needs to know how to export all types of local 145652109Smckusick * exportable file systems and not just MOUNT_UFS. 145752109Smckusick */ 145852109Smckusick while (mount(fsb->f_type, dirp, 145952109Smckusick fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 146051898Smckusick if (cp) 146151898Smckusick *cp-- = savedc; 146251898Smckusick else 146351898Smckusick cp = dirp + dirplen - 1; 146451667Smckusick if (errno == EPERM) { 146551667Smckusick syslog(LOG_ERR, 146651898Smckusick "Can't change attributes for %s.\n", dirp); 146751898Smckusick return (1); 146851667Smckusick } 146951898Smckusick if (opt_flags & OP_ALLDIRS) { 147051898Smckusick syslog(LOG_ERR, "Not root dir"); 147151898Smckusick return (1); 147251898Smckusick } 147351667Smckusick /* back up over the last component */ 147451898Smckusick while (*cp == '/' && cp > dirp) 147551667Smckusick cp--; 147651898Smckusick while (*(cp - 1) != '/' && cp > dirp) 147751667Smckusick cp--; 147851898Smckusick if (cp == dirp) { 147951898Smckusick if (debug) 148051667Smckusick fprintf(stderr,"mnt unsucc\n"); 148151898Smckusick syslog(LOG_ERR, "Can't export %s", dirp); 148251898Smckusick return (1); 148351667Smckusick } 148451667Smckusick savedc = *cp; 148551667Smckusick *cp = '\0'; 148651667Smckusick } 148751898Smckusick if (addrp) { 148851667Smckusick ++addrp; 148951898Smckusick if (*addrp == (u_long *)0) 149051667Smckusick done = TRUE; 149151898Smckusick } else 149251898Smckusick done = TRUE; 149351898Smckusick } 149451898Smckusick if (cp) 149551898Smckusick *cp = savedc; 149651898Smckusick return (0); 149751898Smckusick } 149851898Smckusick 149951898Smckusick /* 150051898Smckusick * Translate a net address. 150151898Smckusick */ 150251898Smckusick get_net(cp, net, maskflg) 150351898Smckusick char *cp; 150451898Smckusick struct netmsk *net; 150551898Smckusick int maskflg; 150651898Smckusick { 150751898Smckusick register struct netent *np; 150851898Smckusick register long netaddr; 150951898Smckusick struct in_addr inetaddr, inetaddr2; 151051898Smckusick char *name; 151151898Smckusick 151251898Smckusick if (np = getnetbyname(cp)) 151351898Smckusick inetaddr = inet_makeaddr(np->n_net, 0); 151451898Smckusick else if (isdigit(*cp)) { 151551898Smckusick if ((netaddr = inet_network(cp)) == -1) 151651898Smckusick return (1); 151751898Smckusick inetaddr = inet_makeaddr(netaddr, 0); 151851898Smckusick /* 151951898Smckusick * Due to arbritrary subnet masks, you don't know how many 152051898Smckusick * bits to shift the address to make it into a network, 152151898Smckusick * however you do know how to make a network address into 152251898Smckusick * a host with host == 0 and then compare them. 152351898Smckusick * (What a pest) 152451898Smckusick */ 152551898Smckusick if (!maskflg) { 152651898Smckusick setnetent(0); 152751898Smckusick while (np = getnetent()) { 152851898Smckusick inetaddr2 = inet_makeaddr(np->n_net, 0); 152951898Smckusick if (inetaddr2.s_addr == inetaddr.s_addr) 153051898Smckusick break; 153151898Smckusick } 153251898Smckusick endnetent(); 153351667Smckusick } 153451898Smckusick } else 153551898Smckusick return (1); 153651898Smckusick if (maskflg) 153751898Smckusick net->nt_mask = inetaddr.s_addr; 153851898Smckusick else { 153951898Smckusick if (np) 154051898Smckusick name = np->n_name; 154151898Smckusick else 154251898Smckusick name = inet_ntoa(inetaddr); 154351898Smckusick net->nt_name = (char *)malloc(strlen(name) + 1); 154451898Smckusick if (net->nt_name == (char *)0) 154551898Smckusick out_of_mem(); 154651898Smckusick strcpy(net->nt_name, name); 154751898Smckusick net->nt_net = inetaddr.s_addr; 154838460Smckusick } 154951898Smckusick return (0); 155038460Smckusick } 155138460Smckusick 155238460Smckusick /* 155338460Smckusick * Parse out the next white space separated field 155438460Smckusick */ 155551667Smckusick void 155638460Smckusick nextfield(cp, endcp) 155738460Smckusick char **cp; 155838460Smckusick char **endcp; 155938460Smckusick { 156038460Smckusick register char *p; 156138460Smckusick 156238460Smckusick p = *cp; 156338460Smckusick while (*p == ' ' || *p == '\t') 156438460Smckusick p++; 156551898Smckusick if (*p == '\n' || *p == '\0') 156638460Smckusick *cp = *endcp = p; 156751898Smckusick else { 156851898Smckusick *cp = p++; 156951898Smckusick while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 157051898Smckusick p++; 157151898Smckusick *endcp = p; 157238460Smckusick } 157338460Smckusick } 157439681Smckusick 157539681Smckusick /* 157651898Smckusick * Get an exports file line. Skip over blank lines and handle line 157751898Smckusick * continuations. 157839681Smckusick */ 157951898Smckusick get_line() 158039681Smckusick { 158151898Smckusick register char *p, *cp; 158251898Smckusick register int len; 158351898Smckusick int totlen, cont_line; 158439681Smckusick 158551898Smckusick /* 158651898Smckusick * Loop around ignoring blank lines and getting all continuation lines. 158751898Smckusick */ 158851898Smckusick p = line; 158951898Smckusick totlen = 0; 159051898Smckusick do { 159151898Smckusick if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 159251898Smckusick return (0); 159351898Smckusick len = strlen(p); 159451898Smckusick cp = p + len - 1; 159551898Smckusick cont_line = 0; 159651898Smckusick while (cp >= p && 159751898Smckusick (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 159851898Smckusick if (*cp == '\\') 159951898Smckusick cont_line = 1; 160051898Smckusick cp--; 160151898Smckusick len--; 160251898Smckusick } 160351898Smckusick *++cp = '\0'; 160451898Smckusick if (len > 0) { 160551898Smckusick totlen += len; 160651898Smckusick if (totlen >= LINESIZ) { 160751898Smckusick syslog(LOG_ERR, "Exports line too long"); 160851898Smckusick exit(2); 160951898Smckusick } 161051898Smckusick p = cp; 161151898Smckusick } 161251898Smckusick } while (totlen == 0 || cont_line); 161351898Smckusick return (1); 161444015Smckusick } 161544015Smckusick 161651667Smckusick /* 161751667Smckusick * Parse a description of a credential. 161851667Smckusick */ 161951667Smckusick parsecred(namelist, cr) 162051667Smckusick char *namelist; 162151667Smckusick register struct ucred *cr; 162251667Smckusick { 162351667Smckusick register char *name; 162451667Smckusick register int cnt; 162551667Smckusick char *names; 162651667Smckusick struct passwd *pw; 162751667Smckusick struct group *gr; 162851667Smckusick int ngroups, groups[NGROUPS + 1]; 162951667Smckusick 163051667Smckusick /* 163151667Smckusick * Set up the unpriviledged user. 163251667Smckusick */ 163351667Smckusick cr->cr_ref = 1; 163451667Smckusick cr->cr_uid = -2; 163551667Smckusick cr->cr_groups[0] = -2; 163651667Smckusick cr->cr_ngroups = 1; 163751667Smckusick /* 163851667Smckusick * Get the user's password table entry. 163951667Smckusick */ 164051667Smckusick names = strsep(&namelist, " \t\n"); 164151667Smckusick name = strsep(&names, ":"); 164251667Smckusick if (isdigit(*name) || *name == '-') 164351667Smckusick pw = getpwuid(atoi(name)); 164451667Smckusick else 164551667Smckusick pw = getpwnam(name); 164651667Smckusick /* 164751667Smckusick * Credentials specified as those of a user. 164851667Smckusick */ 164951667Smckusick if (names == NULL) { 165051667Smckusick if (pw == NULL) { 165151667Smckusick syslog(LOG_ERR, "Unknown user: %s\n", name); 165251667Smckusick return; 165351667Smckusick } 165451667Smckusick cr->cr_uid = pw->pw_uid; 165551667Smckusick ngroups = NGROUPS + 1; 165651667Smckusick if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 165751667Smckusick syslog(LOG_ERR, "Too many groups\n"); 165851667Smckusick /* 165951667Smckusick * Convert from int's to gid_t's and compress out duplicate 166051667Smckusick */ 166151667Smckusick cr->cr_ngroups = ngroups - 1; 166251667Smckusick cr->cr_groups[0] = groups[0]; 166351667Smckusick for (cnt = 2; cnt < ngroups; cnt++) 166451667Smckusick cr->cr_groups[cnt - 1] = groups[cnt]; 166551667Smckusick return; 166651667Smckusick } 166751667Smckusick /* 166851667Smckusick * Explicit credential specified as a colon separated list: 166951667Smckusick * uid:gid:gid:... 167051667Smckusick */ 167151667Smckusick if (pw != NULL) 167251667Smckusick cr->cr_uid = pw->pw_uid; 167351667Smckusick else if (isdigit(*name) || *name == '-') 167451667Smckusick cr->cr_uid = atoi(name); 167551667Smckusick else { 167651667Smckusick syslog(LOG_ERR, "Unknown user: %s\n", name); 167751667Smckusick return; 167851667Smckusick } 167951667Smckusick cr->cr_ngroups = 0; 168051667Smckusick while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 168151667Smckusick name = strsep(&names, ":"); 168251667Smckusick if (isdigit(*name) || *name == '-') { 168351667Smckusick cr->cr_groups[cr->cr_ngroups++] = atoi(name); 168451667Smckusick } else { 168551667Smckusick if ((gr = getgrnam(name)) == NULL) { 168651667Smckusick syslog(LOG_ERR, "Unknown group: %s\n", name); 168751667Smckusick continue; 168851667Smckusick } 168951667Smckusick cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 169051667Smckusick } 169151667Smckusick } 169251667Smckusick if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 169351667Smckusick syslog(LOG_ERR, "Too many groups\n"); 169451667Smckusick } 169551667Smckusick 169644015Smckusick #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 169744015Smckusick /* 169844015Smckusick * Routines that maintain the remote mounttab 169944015Smckusick */ 170051667Smckusick void 170151667Smckusick get_mountlist() 170244015Smckusick { 170344015Smckusick register struct mountlist *mlp, **mlpp; 170444015Smckusick register char *eos, *dirp; 170544015Smckusick int len; 170644015Smckusick char str[STRSIZ]; 170744015Smckusick FILE *mlfile; 170844015Smckusick 170951712Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 171051667Smckusick syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 171144015Smckusick return; 171244015Smckusick } 171344015Smckusick mlpp = &mlhead; 171444015Smckusick while (fgets(str, STRSIZ, mlfile) != NULL) { 171544015Smckusick if ((dirp = index(str, '\t')) == NULL && 171644015Smckusick (dirp = index(str, ' ')) == NULL) 171744015Smckusick continue; 171844015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 171944015Smckusick len = dirp-str; 172044015Smckusick if (len > RPCMNT_NAMELEN) 172144015Smckusick len = RPCMNT_NAMELEN; 172244015Smckusick bcopy(str, mlp->ml_host, len); 172344015Smckusick mlp->ml_host[len] = '\0'; 172444015Smckusick while (*dirp == '\t' || *dirp == ' ') 172544015Smckusick dirp++; 172644015Smckusick if ((eos = index(dirp, '\t')) == NULL && 172744015Smckusick (eos = index(dirp, ' ')) == NULL && 172844015Smckusick (eos = index(dirp, '\n')) == NULL) 172944015Smckusick len = strlen(dirp); 173044015Smckusick else 173144015Smckusick len = eos-dirp; 173244015Smckusick if (len > RPCMNT_PATHLEN) 173344015Smckusick len = RPCMNT_PATHLEN; 173444015Smckusick bcopy(dirp, mlp->ml_dirp, len); 173544015Smckusick mlp->ml_dirp[len] = '\0'; 173644015Smckusick mlp->ml_next = (struct mountlist *)0; 173744015Smckusick *mlpp = mlp; 173844015Smckusick mlpp = &mlp->ml_next; 173944015Smckusick } 174044015Smckusick fclose(mlfile); 174144015Smckusick } 174244015Smckusick 174351667Smckusick void 174451667Smckusick del_mlist(hostp, dirp) 174544015Smckusick register char *hostp, *dirp; 174644015Smckusick { 174744015Smckusick register struct mountlist *mlp, **mlpp; 174851712Smckusick struct mountlist *mlp2; 174944015Smckusick FILE *mlfile; 175044015Smckusick int fnd = 0; 175144015Smckusick 175244015Smckusick mlpp = &mlhead; 175344015Smckusick mlp = mlhead; 175444015Smckusick while (mlp) { 175544015Smckusick if (!strcmp(mlp->ml_host, hostp) && 175644015Smckusick (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 175744015Smckusick fnd = 1; 175851712Smckusick mlp2 = mlp; 175951712Smckusick *mlpp = mlp = mlp->ml_next; 176051712Smckusick free((caddr_t)mlp2); 176151712Smckusick } else { 176251712Smckusick mlpp = &mlp->ml_next; 176351712Smckusick mlp = mlp->ml_next; 176439681Smckusick } 176539681Smckusick } 176644015Smckusick if (fnd) { 176744015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 176851898Smckusick syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 176944015Smckusick return; 177044015Smckusick } 177144015Smckusick mlp = mlhead; 177244015Smckusick while (mlp) { 177344015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 177444015Smckusick mlp = mlp->ml_next; 177544015Smckusick } 177644015Smckusick fclose(mlfile); 177744015Smckusick } 177839681Smckusick } 177944015Smckusick 178051667Smckusick void 178151667Smckusick add_mlist(hostp, dirp) 178244015Smckusick register char *hostp, *dirp; 178344015Smckusick { 178444015Smckusick register struct mountlist *mlp, **mlpp; 178544015Smckusick FILE *mlfile; 178644015Smckusick 178744015Smckusick mlpp = &mlhead; 178844015Smckusick mlp = mlhead; 178944015Smckusick while (mlp) { 179044015Smckusick if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 179144015Smckusick return; 179244015Smckusick mlpp = &mlp->ml_next; 179344015Smckusick mlp = mlp->ml_next; 179444015Smckusick } 179544015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 179644015Smckusick strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 179744015Smckusick mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 179844015Smckusick strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 179944015Smckusick mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 180044015Smckusick mlp->ml_next = (struct mountlist *)0; 180144015Smckusick *mlpp = mlp; 180244015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 180351898Smckusick syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 180444015Smckusick return; 180544015Smckusick } 180644015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 180744015Smckusick fclose(mlfile); 180844015Smckusick } 180944015Smckusick 181044015Smckusick /* 181144015Smckusick * This function is called via. SIGTERM when the system is going down. 181244015Smckusick * It sends a broadcast RPCMNT_UMNTALL. 181344015Smckusick */ 181446709Sbostic void 181544015Smckusick send_umntall() 181644015Smckusick { 181744015Smckusick (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 181844015Smckusick xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 181951667Smckusick exit(0); 182044015Smckusick } 182144015Smckusick 182244015Smckusick umntall_each(resultsp, raddr) 182344015Smckusick caddr_t resultsp; 182444015Smckusick struct sockaddr_in *raddr; 182544015Smckusick { 182644015Smckusick return (1); 182744015Smckusick } 182844015Smckusick 182944015Smckusick /* 183051667Smckusick * Free up a group list. 183151667Smckusick */ 183251667Smckusick void 183351667Smckusick free_grp(grp) 183451667Smckusick register struct grouplist *grp; 183551667Smckusick { 183651667Smckusick register char **addrp; 183751667Smckusick 183851898Smckusick if (grp->gr_type == GT_HOST) { 183951712Smckusick if (grp->gr_ptr.gt_hostent->h_name) { 184051712Smckusick addrp = grp->gr_ptr.gt_hostent->h_addr_list; 184151712Smckusick while (addrp && *addrp) 184251712Smckusick free(*addrp++); 184351712Smckusick free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 184451712Smckusick free(grp->gr_ptr.gt_hostent->h_name); 184551712Smckusick } 184651667Smckusick free((caddr_t)grp->gr_ptr.gt_hostent); 184751898Smckusick } else if (grp->gr_type == GT_NET) { 184851898Smckusick if (grp->gr_ptr.gt_net.nt_name) 184951898Smckusick free(grp->gr_ptr.gt_net.nt_name); 185051667Smckusick } 185151667Smckusick #ifdef ISO 185251898Smckusick else if (grp->gr_type == GT_ISO) 185351667Smckusick free((caddr_t)grp->gr_ptr.gt_isoaddr); 185451667Smckusick #endif 185551667Smckusick free((caddr_t)grp); 185651667Smckusick } 185751667Smckusick 185851667Smckusick /* 185951667Smckusick * char *realpath(const char *path, char resolved_path[MAXPATHLEN]) 186051667Smckusick * 186151667Smckusick * find the real name of path, by removing all ".", ".." 186251667Smckusick * and symlink components. 186351667Smckusick * 186451667Smckusick * Jan-Simon Pendry, September 1991. 186551667Smckusick */ 186651667Smckusick char * 186751667Smckusick realpath(path, resolved) 186851667Smckusick char *path; 186951667Smckusick char resolved[MAXPATHLEN]; 187051667Smckusick { 187151667Smckusick int d = open(".", O_RDONLY); 187251667Smckusick int rootd = 0; 187351667Smckusick char *p, *q; 187451667Smckusick struct stat stb; 187551667Smckusick char wbuf[MAXPATHLEN]; 187651667Smckusick 187751667Smckusick strcpy(resolved, path); 187851667Smckusick 187951667Smckusick if (d < 0) 188051667Smckusick return 0; 188151667Smckusick 188251667Smckusick loop:; 188351667Smckusick q = strrchr(resolved, '/'); 188451667Smckusick if (q) { 188551667Smckusick p = q + 1; 188651667Smckusick if (q == resolved) 188751667Smckusick q = "/"; 188851667Smckusick else { 188951667Smckusick do 189051667Smckusick --q; 189151667Smckusick while (q > resolved && *q == '/'); 189251667Smckusick q[1] = '\0'; 189351667Smckusick q = resolved; 189451667Smckusick } 189551667Smckusick if (chdir(q) < 0) 189651667Smckusick goto out; 189751667Smckusick } else 189851667Smckusick p = resolved; 189951667Smckusick 190051667Smckusick if (lstat(p, &stb) == 0) { 190151667Smckusick if (S_ISLNK(stb.st_mode)) { 190251667Smckusick int n = readlink(p, resolved, MAXPATHLEN); 190351667Smckusick if (n < 0) 190451667Smckusick goto out; 190551667Smckusick resolved[n] = '\0'; 190651667Smckusick goto loop; 190751667Smckusick } 190851667Smckusick if (S_ISDIR(stb.st_mode)) { 190951667Smckusick if (chdir(p) < 0) 191051667Smckusick goto out; 191151667Smckusick p = ""; 191251667Smckusick } 191351667Smckusick } 191451667Smckusick 191551667Smckusick strcpy(wbuf, p); 191651667Smckusick if (getcwd(resolved, MAXPATHLEN) == 0) 191751667Smckusick goto out; 191851667Smckusick if (resolved[0] == '/' && resolved[1] == '\0') 191951667Smckusick rootd = 1; 192051667Smckusick 192151667Smckusick if (*wbuf) { 192251667Smckusick if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) { 192351667Smckusick errno = ENAMETOOLONG; 192451667Smckusick goto out; 192551667Smckusick } 192651667Smckusick if (rootd == 0) 192751667Smckusick strcat(resolved, "/"); 192851667Smckusick strcat(resolved, wbuf); 192951667Smckusick } 193051667Smckusick 193151667Smckusick if (fchdir(d) < 0) 193251667Smckusick goto out; 193351667Smckusick (void) close(d); 193451667Smckusick 193551667Smckusick return resolved; 193651667Smckusick 193751667Smckusick out:; 193851667Smckusick (void) close(d); 193951667Smckusick return 0; 194051667Smckusick } 194151711Smckusick 194251711Smckusick #ifdef DEBUG 194351711Smckusick void 194451711Smckusick SYSLOG(int pri, const char *fmt, ...) 194551711Smckusick { 194651711Smckusick va_list ap; 194751711Smckusick 194851711Smckusick va_start(ap, fmt); 194951711Smckusick vfprintf(stderr, fmt, ap); 195051711Smckusick va_end(ap); 195151711Smckusick } 195251711Smckusick #endif /* DEBUG */ 195351898Smckusick 195451898Smckusick /* 195551898Smckusick * Check options for consistency. 195651898Smckusick */ 195751898Smckusick check_options(dp) 195851898Smckusick struct dirlist *dp; 195951898Smckusick { 196051898Smckusick 196151898Smckusick if (dp == (struct dirlist *)0) 196251898Smckusick return (1); 196351898Smckusick if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 196451898Smckusick (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 196551898Smckusick (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 196651898Smckusick syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 196751898Smckusick return (1); 196851898Smckusick } 196951898Smckusick if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 197051898Smckusick syslog(LOG_ERR, "-mask requires -net"); 197151898Smckusick return (1); 197251898Smckusick } 197351898Smckusick if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 197451898Smckusick syslog(LOG_ERR, "-net and -iso mutually exclusive"); 197551898Smckusick return (1); 197651898Smckusick } 197751898Smckusick if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 197851898Smckusick syslog(LOG_ERR, "-alldir has multiple directories"); 197951898Smckusick return (1); 198051898Smckusick } 198151898Smckusick return (0); 198251898Smckusick } 1983*65940Sbostic 1984*65940Sbostic /* 1985*65940Sbostic * Check an absolute directory path for any symbolic links. Return true 1986*65940Sbostic * if no symbolic links are found. 1987*65940Sbostic */ 1988*65940Sbostic int 1989*65940Sbostic check_dirpath(dirp) 1990*65940Sbostic register char *dirp; 1991*65940Sbostic { 1992*65940Sbostic register char *cp; 1993*65940Sbostic int ret = 1; 1994*65940Sbostic struct stat sb; 1995*65940Sbostic 1996*65940Sbostic cp = dirp + 1; 1997*65940Sbostic while (*cp && ret) { 1998*65940Sbostic if (*cp == '/') { 1999*65940Sbostic *cp = '\0'; 2000*65940Sbostic if (lstat(dirp, &sb) < 0 || 2001*65940Sbostic (sb.st_mode & S_IFMT) != S_IFDIR) 2002*65940Sbostic ret = 0; 2003*65940Sbostic *cp = '/'; 2004*65940Sbostic } 2005*65940Sbostic cp++; 2006*65940Sbostic } 2007*65940Sbostic if (lstat(dirp, &sb) < 0 || 2008*65940Sbostic (sb.st_mode & S_IFMT) != S_IFDIR) 2009*65940Sbostic ret = 0; 2010*65940Sbostic return (ret); 2011*65940Sbostic } 2012