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*64903Smckusick static char sccsid[] = "@(#)mountd.c 8.2 (Berkeley) 11/16/93"; 1938460Smckusick #endif not lint 2038460Smckusick 2151667Smckusick #include <pwd.h> 2251667Smckusick #include <grp.h> 2351667Smckusick #include <unistd.h> 2451667Smckusick #include <stdlib.h> 2538460Smckusick #include <sys/param.h> 2638460Smckusick #include <sys/ioctl.h> 2738460Smckusick #include <sys/stat.h> 2839681Smckusick #include <sys/file.h> 2951667Smckusick #include <sys/ucred.h> 3038460Smckusick #include <sys/mount.h> 3138460Smckusick #include <sys/socket.h> 3238460Smckusick #include <sys/errno.h> 3342038Sbostic #include <sys/signal.h> 3442038Sbostic #include <stdio.h> 3542038Sbostic #include <string.h> 3652109Smckusick #include <sys/syslog.h> 3738460Smckusick #include <netdb.h> 3838460Smckusick #include <rpc/rpc.h> 3938460Smckusick #include <rpc/pmap_clnt.h> 4038460Smckusick #include <rpc/pmap_prot.h> 4151667Smckusick #ifdef ISO 4251667Smckusick #include <netiso/iso.h> 4351667Smckusick #endif 4438460Smckusick #include <nfs/rpcv2.h> 4538460Smckusick #include <nfs/nfsv2.h> 4639681Smckusick #include "pathnames.h" 4753150Smckusick #ifdef DEBUG 4853150Smckusick #include <stdarg.h> 4953150Smckusick #endif 5038460Smckusick 5138460Smckusick /* 5238460Smckusick * Structures for keeping the mount list and export list 5338460Smckusick */ 5438460Smckusick struct mountlist { 5544015Smckusick struct mountlist *ml_next; 5638460Smckusick char ml_host[RPCMNT_NAMELEN+1]; 5738460Smckusick char ml_dirp[RPCMNT_PATHLEN+1]; 5838460Smckusick }; 5938460Smckusick 6051898Smckusick struct dirlist { 6151898Smckusick struct dirlist *dp_left; 6251898Smckusick struct dirlist *dp_right; 6351898Smckusick int dp_flag; 6451898Smckusick struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 6551898Smckusick char dp_dirp[1]; /* Actually malloc'd to size of dir */ 6651898Smckusick }; 6751898Smckusick /* dp_flag bits */ 6851898Smckusick #define DP_DEFSET 0x1 6951898Smckusick 7038460Smckusick struct exportlist { 7138460Smckusick struct exportlist *ex_next; 7251898Smckusick struct dirlist *ex_dirl; 7351898Smckusick struct dirlist *ex_defdir; 7451898Smckusick int ex_flag; 7551898Smckusick fsid_t ex_fs; 7651898Smckusick char *ex_fsdir; 7738460Smckusick }; 7851898Smckusick /* ex_flag bits */ 7952109Smckusick #define EX_LINKED 0x1 8038460Smckusick 8151898Smckusick struct netmsk { 8251898Smckusick u_long nt_net; 8351898Smckusick u_long nt_mask; 8451898Smckusick char *nt_name; 8551898Smckusick }; 8651898Smckusick 8751667Smckusick union grouptypes { 8851667Smckusick struct hostent *gt_hostent; 8951898Smckusick struct netmsk gt_net; 9051667Smckusick #ifdef ISO 9151667Smckusick struct sockaddr_iso *gt_isoaddr; 9251667Smckusick #endif 9351667Smckusick }; 9451667Smckusick 9538460Smckusick struct grouplist { 9651898Smckusick int gr_type; 9751667Smckusick union grouptypes gr_ptr; 9838460Smckusick struct grouplist *gr_next; 9938460Smckusick }; 10051898Smckusick /* Group types */ 10151898Smckusick #define GT_NULL 0x0 10251898Smckusick #define GT_HOST 0x1 10351898Smckusick #define GT_NET 0x2 10451898Smckusick #define GT_ISO 0x4 10538460Smckusick 10651898Smckusick struct hostlist { 10751898Smckusick struct grouplist *ht_grp; 10851898Smckusick struct hostlist *ht_next; 10951667Smckusick }; 11051667Smckusick 11138460Smckusick /* Global defs */ 11246709Sbostic int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist(); 11351898Smckusick void get_exportlist(), send_umntall(), nextfield(), out_of_mem(); 11451667Smckusick void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp(); 11551898Smckusick void getexp_err(), hang_dirp(), add_dlist(), free_dir(), free_host(); 11653150Smckusick void setnetgrent(), endnetgrent(); 11751898Smckusick struct exportlist *ex_search(), *get_exp(); 11851898Smckusick struct grouplist *get_grp(); 11951898Smckusick char *realpath(), *add_expdir(); 12051898Smckusick struct in_addr inet_makeaddr(); 12151898Smckusick char *inet_ntoa(); 12251898Smckusick struct dirlist *dirp_search(); 12351898Smckusick struct hostlist *get_ht(); 12451667Smckusick #ifdef ISO 12551667Smckusick struct iso_addr *iso_addr(); 12651667Smckusick #endif 12751898Smckusick struct exportlist *exphead; 12844015Smckusick struct mountlist *mlhead; 12951898Smckusick struct grouplist *grphead; 13038460Smckusick char exname[MAXPATHLEN]; 13151667Smckusick struct ucred def_anon = { 13251667Smckusick (u_short) 1, 13351667Smckusick (uid_t) -2, 13451667Smckusick 1, 13551667Smckusick (gid_t) -2, 13651667Smckusick }; 13744015Smckusick int root_only = 1; 13851898Smckusick int opt_flags; 13951898Smckusick /* Bits for above */ 14051898Smckusick #define OP_MAPROOT 0x01 14151898Smckusick #define OP_MAPALL 0x02 14251898Smckusick #define OP_KERB 0x04 14351898Smckusick #define OP_MASK 0x08 14451898Smckusick #define OP_NET 0x10 14551898Smckusick #define OP_ISO 0x20 14651898Smckusick #define OP_ALLDIRS 0x40 14751898Smckusick 14838460Smckusick extern int errno; 14938460Smckusick #ifdef DEBUG 15038460Smckusick int debug = 1; 15151711Smckusick void SYSLOG __P((int, const char *, ...)); 15251711Smckusick #define syslog SYSLOG 15338460Smckusick #else 15438460Smckusick int debug = 0; 15538460Smckusick #endif 15638460Smckusick 15738460Smckusick /* 15838460Smckusick * Mountd server for NFS mount protocol as described in: 15939681Smckusick * NFS: Network File System Protocol Specification, RFC1094, Appendix A 16044015Smckusick * The optional arguments are the exports file name 16139681Smckusick * default: _PATH_EXPORTS 16244015Smckusick * and "-n" to allow nonroot mount. 16338460Smckusick */ 16438460Smckusick main(argc, argv) 16538460Smckusick int argc; 16644015Smckusick char **argv; 16738460Smckusick { 16838460Smckusick SVCXPRT *transp; 16944015Smckusick int c; 17044015Smckusick extern int optind; 17144015Smckusick extern char *optarg; 17238460Smckusick 17344015Smckusick while ((c = getopt(argc, argv, "n")) != EOF) 17444015Smckusick switch (c) { 17544015Smckusick case 'n': 17644015Smckusick root_only = 0; 17744015Smckusick break; 17844015Smckusick default: 17944015Smckusick fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); 18044015Smckusick exit(1); 18144015Smckusick }; 18244015Smckusick argc -= optind; 18344015Smckusick argv += optind; 18451898Smckusick grphead = (struct grouplist *)0; 18551898Smckusick exphead = (struct exportlist *)0; 18644015Smckusick mlhead = (struct mountlist *)0; 18744015Smckusick if (argc == 1) { 18844015Smckusick strncpy(exname, *argv, MAXPATHLEN-1); 18944015Smckusick exname[MAXPATHLEN-1] = '\0'; 19044015Smckusick } else 19144015Smckusick strcpy(exname, _PATH_EXPORTS); 19244338Smckusick openlog("mountd:", LOG_PID, LOG_DAEMON); 19351667Smckusick if (debug) 19451667Smckusick fprintf(stderr,"Getting export list.\n"); 19544015Smckusick get_exportlist(); 19651667Smckusick if (debug) 19751667Smckusick fprintf(stderr,"Getting mount list.\n"); 19844015Smckusick get_mountlist(); 19951667Smckusick if (debug) 20051667Smckusick fprintf(stderr,"Here we go.\n"); 20138460Smckusick if (debug == 0) { 20244690Skarels daemon(0, 0); 20338460Smckusick signal(SIGINT, SIG_IGN); 20438460Smckusick signal(SIGQUIT, SIG_IGN); 20538460Smckusick } 20638460Smckusick signal(SIGHUP, get_exportlist); 20744015Smckusick signal(SIGTERM, send_umntall); 20840494Smckusick { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 20940494Smckusick if (pidfile != NULL) { 21040494Smckusick fprintf(pidfile, "%d\n", getpid()); 21140494Smckusick fclose(pidfile); 21240494Smckusick } 21340494Smckusick } 21438460Smckusick if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { 21538460Smckusick syslog(LOG_ERR, "Can't create socket"); 21638460Smckusick exit(1); 21738460Smckusick } 21838460Smckusick pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 21951667Smckusick if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 22051667Smckusick IPPROTO_UDP)) { 22138460Smckusick syslog(LOG_ERR, "Can't register mount"); 22238460Smckusick exit(1); 22338460Smckusick } 22438460Smckusick svc_run(); 22538460Smckusick syslog(LOG_ERR, "Mountd died"); 22644690Skarels exit(1); 22738460Smckusick } 22838460Smckusick 22938460Smckusick /* 23038460Smckusick * The mount rpc service 23138460Smckusick */ 23238460Smckusick mntsrv(rqstp, transp) 23338460Smckusick register struct svc_req *rqstp; 23438460Smckusick register SVCXPRT *transp; 23538460Smckusick { 23638460Smckusick register struct exportlist *ep; 23751898Smckusick register struct dirlist *dp; 23838460Smckusick nfsv2fh_t nfh; 23938460Smckusick struct authunix_parms *ucr; 24038460Smckusick struct stat stb; 24151898Smckusick struct statfs fsb; 24238460Smckusick struct hostent *hp; 24339681Smckusick u_long saddr; 24451667Smckusick char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; 24551898Smckusick int bad = ENOENT, omask, defset; 24639681Smckusick uid_t uid = -2; 24738460Smckusick 24838460Smckusick /* Get authorization */ 24938460Smckusick switch (rqstp->rq_cred.oa_flavor) { 25038460Smckusick case AUTH_UNIX: 25138460Smckusick ucr = (struct authunix_parms *)rqstp->rq_clntcred; 25239681Smckusick uid = ucr->aup_uid; 25339681Smckusick break; 25438460Smckusick case AUTH_NULL: 25538460Smckusick default: 25639681Smckusick break; 25738460Smckusick } 25838460Smckusick 25939681Smckusick saddr = transp->xp_raddr.sin_addr.s_addr; 26039681Smckusick hp = (struct hostent *)0; 26138460Smckusick switch (rqstp->rq_proc) { 26239681Smckusick case NULLPROC: 26339681Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 26439681Smckusick syslog(LOG_ERR, "Can't send reply"); 26539681Smckusick return; 26638460Smckusick case RPCMNT_MOUNT: 26751667Smckusick if ((uid != 0 && root_only) || uid == -2) { 26839681Smckusick svcerr_weakauth(transp); 26939681Smckusick return; 27039681Smckusick } 27151667Smckusick if (!svc_getargs(transp, xdr_dir, rpcpath)) { 27238460Smckusick svcerr_decode(transp); 27338460Smckusick return; 27438460Smckusick } 27538460Smckusick 27651667Smckusick /* 27751667Smckusick * Get the real pathname and make sure it is a directory 27851667Smckusick * that exists. 27951667Smckusick */ 28051898Smckusick if (realpath(rpcpath, dirpath) == 0 || 28151898Smckusick stat(dirpath, &stb) < 0 || 28251898Smckusick (stb.st_mode & S_IFMT) != S_IFDIR || 28351898Smckusick statfs(dirpath, &fsb) < 0) { 28451667Smckusick chdir("/"); /* Just in case realpath doesn't */ 28551667Smckusick if (debug) 28651898Smckusick fprintf(stderr, "stat failed on %s\n", dirpath); 28738460Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 28838460Smckusick syslog(LOG_ERR, "Can't send reply"); 28938460Smckusick return; 29038460Smckusick } 29138460Smckusick 29238460Smckusick /* Check in the exports list */ 29338460Smckusick omask = sigblock(sigmask(SIGHUP)); 29451898Smckusick ep = ex_search(&fsb.f_fsid); 29551898Smckusick defset = 0; 29651898Smckusick if (ep && (chk_host(ep->ex_defdir, saddr, &defset) || 29751898Smckusick ((dp = dirp_search(ep->ex_dirl, dirpath)) && 29851898Smckusick chk_host(dp, saddr, &defset)) || 29951898Smckusick (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 30051898Smckusick scan_tree(ep->ex_dirl, saddr) == 0))) { 30151667Smckusick /* Get the file handle */ 30251667Smckusick bzero((caddr_t)&nfh, sizeof(nfh)); 30351667Smckusick if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { 30451667Smckusick bad = errno; 30551898Smckusick syslog(LOG_ERR, "Can't get fh for %s", dirpath); 30651667Smckusick if (!svc_sendreply(transp, xdr_long, 30751667Smckusick (caddr_t)&bad)) 30851667Smckusick syslog(LOG_ERR, "Can't send reply"); 30951667Smckusick sigsetmask(omask); 31051667Smckusick return; 31151667Smckusick } 31251667Smckusick if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) 31338460Smckusick syslog(LOG_ERR, "Can't send reply"); 31451667Smckusick if (hp == NULL) 31551667Smckusick hp = gethostbyaddr((caddr_t)&saddr, 31651667Smckusick sizeof(saddr), AF_INET); 31751667Smckusick if (hp) 31851667Smckusick add_mlist(hp->h_name, dirpath); 31951667Smckusick else 32051667Smckusick add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 32151667Smckusick dirpath); 32251667Smckusick if (debug) 32351667Smckusick fprintf(stderr,"Mount successfull.\n"); 32451898Smckusick } else { 32551898Smckusick bad = EACCES; 32651898Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 32751898Smckusick syslog(LOG_ERR, "Can't send reply"); 32838460Smckusick } 32951667Smckusick sigsetmask(omask); 33038460Smckusick return; 33138460Smckusick case RPCMNT_DUMP: 33238460Smckusick if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0)) 33338460Smckusick syslog(LOG_ERR, "Can't send reply"); 33438460Smckusick return; 33538460Smckusick case RPCMNT_UMOUNT: 33651667Smckusick if ((uid != 0 && root_only) || uid == -2) { 33739681Smckusick svcerr_weakauth(transp); 33839681Smckusick return; 33939681Smckusick } 34038460Smckusick if (!svc_getargs(transp, xdr_dir, dirpath)) { 34138460Smckusick svcerr_decode(transp); 34238460Smckusick return; 34338460Smckusick } 34438460Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 34538460Smckusick syslog(LOG_ERR, "Can't send reply"); 34644015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 34744015Smckusick if (hp) 34844015Smckusick del_mlist(hp->h_name, dirpath); 34951667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 35038460Smckusick return; 35138460Smckusick case RPCMNT_UMNTALL: 35251667Smckusick if ((uid != 0 && root_only) || uid == -2) { 35339681Smckusick svcerr_weakauth(transp); 35439681Smckusick return; 35539681Smckusick } 35638460Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 35738460Smckusick syslog(LOG_ERR, "Can't send reply"); 35844015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 35944015Smckusick if (hp) 36044015Smckusick del_mlist(hp->h_name, (char *)0); 36151667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)0); 36238460Smckusick return; 36338460Smckusick case RPCMNT_EXPORT: 36438460Smckusick if (!svc_sendreply(transp, xdr_explist, (caddr_t)0)) 36538460Smckusick syslog(LOG_ERR, "Can't send reply"); 36638460Smckusick return; 36738460Smckusick default: 36838460Smckusick svcerr_noproc(transp); 36938460Smckusick return; 37038460Smckusick } 37138460Smckusick } 37238460Smckusick 37338460Smckusick /* 37438460Smckusick * Xdr conversion for a dirpath string 37538460Smckusick */ 37638460Smckusick xdr_dir(xdrsp, dirp) 37738460Smckusick XDR *xdrsp; 37838460Smckusick char *dirp; 37938460Smckusick { 38038460Smckusick return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 38138460Smckusick } 38238460Smckusick 38338460Smckusick /* 38438460Smckusick * Xdr routine to generate fhstatus 38538460Smckusick */ 38638460Smckusick xdr_fhs(xdrsp, nfh) 38738460Smckusick XDR *xdrsp; 38838460Smckusick nfsv2fh_t *nfh; 38938460Smckusick { 39038460Smckusick int ok = 0; 39138460Smckusick 39238460Smckusick if (!xdr_long(xdrsp, &ok)) 39338460Smckusick return (0); 39438460Smckusick return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); 39538460Smckusick } 39638460Smckusick 39738460Smckusick xdr_mlist(xdrsp, cp) 39838460Smckusick XDR *xdrsp; 39938460Smckusick caddr_t cp; 40038460Smckusick { 40144015Smckusick register struct mountlist *mlp; 40238460Smckusick int true = 1; 40338460Smckusick int false = 0; 40438460Smckusick char *strp; 40538460Smckusick 40644015Smckusick mlp = mlhead; 40744015Smckusick while (mlp) { 40844015Smckusick if (!xdr_bool(xdrsp, &true)) 40944015Smckusick return (0); 41044015Smckusick strp = &mlp->ml_host[0]; 41144015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 41244015Smckusick return (0); 41344015Smckusick strp = &mlp->ml_dirp[0]; 41444015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 41544015Smckusick return (0); 41644015Smckusick mlp = mlp->ml_next; 41738460Smckusick } 41838460Smckusick if (!xdr_bool(xdrsp, &false)) 41938460Smckusick return (0); 42038460Smckusick return (1); 42138460Smckusick } 42238460Smckusick 42338460Smckusick /* 42438460Smckusick * Xdr conversion for export list 42538460Smckusick */ 42638460Smckusick xdr_explist(xdrsp, cp) 42738460Smckusick XDR *xdrsp; 42838460Smckusick caddr_t cp; 42938460Smckusick { 43038460Smckusick register struct exportlist *ep; 43138460Smckusick int false = 0; 432*64903Smckusick int omask, putdef; 43338460Smckusick 43438460Smckusick omask = sigblock(sigmask(SIGHUP)); 43551898Smckusick ep = exphead; 43651898Smckusick while (ep) { 437*64903Smckusick putdef = 0; 438*64903Smckusick if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 43938460Smckusick goto errout; 440*64903Smckusick if (ep->ex_defdir && putdef == 0 && 441*64903Smckusick put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)0, 442*64903Smckusick &putdef)) 443*64903Smckusick goto errout; 44438460Smckusick ep = ep->ex_next; 44538460Smckusick } 44638460Smckusick sigsetmask(omask); 44738460Smckusick if (!xdr_bool(xdrsp, &false)) 44838460Smckusick return (0); 44938460Smckusick return (1); 45038460Smckusick errout: 45138460Smckusick sigsetmask(omask); 45238460Smckusick return (0); 45338460Smckusick } 45438460Smckusick 45551898Smckusick /* 45651898Smckusick * Called from xdr_explist() to traverse the tree and export the 45751898Smckusick * directory paths. 45851898Smckusick */ 459*64903Smckusick put_exlist(dp, xdrsp, adp, putdefp) 46051898Smckusick register struct dirlist *dp; 46151898Smckusick XDR *xdrsp; 46251898Smckusick struct dirlist *adp; 463*64903Smckusick int *putdefp; 46451898Smckusick { 46551898Smckusick register struct grouplist *grp; 46651898Smckusick register struct hostlist *hp; 46751898Smckusick struct in_addr inaddr; 46851898Smckusick int true = 1; 46951898Smckusick int false = 0; 47051898Smckusick int gotalldir = 0; 47151898Smckusick char *strp; 47251898Smckusick 47351898Smckusick if (dp) { 474*64903Smckusick if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 47551898Smckusick return (1); 47651898Smckusick if (!xdr_bool(xdrsp, &true)) 47751898Smckusick return (1); 47851898Smckusick strp = dp->dp_dirp; 47951898Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 48051898Smckusick return (1); 481*64903Smckusick if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 48251898Smckusick gotalldir = 1; 483*64903Smckusick *putdefp = 1; 484*64903Smckusick } 48551898Smckusick if ((dp->dp_flag & DP_DEFSET) == 0 && 48651898Smckusick (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 48751898Smckusick hp = dp->dp_hosts; 48851898Smckusick while (hp) { 48951898Smckusick grp = hp->ht_grp; 49051898Smckusick if (grp->gr_type == GT_HOST) { 49151898Smckusick if (!xdr_bool(xdrsp, &true)) 49251898Smckusick return (1); 49351898Smckusick strp = grp->gr_ptr.gt_hostent->h_name; 49451898Smckusick if (!xdr_string(xdrsp, &strp, 49551898Smckusick RPCMNT_NAMELEN)) 49651898Smckusick return (1); 49751898Smckusick } else if (grp->gr_type == GT_NET) { 49851898Smckusick if (!xdr_bool(xdrsp, &true)) 49951898Smckusick return (1); 50051898Smckusick strp = grp->gr_ptr.gt_net.nt_name; 50151898Smckusick if (!xdr_string(xdrsp, &strp, 50251898Smckusick RPCMNT_NAMELEN)) 50351898Smckusick return (1); 50451898Smckusick } 50551898Smckusick hp = hp->ht_next; 50651898Smckusick if (gotalldir && hp == (struct hostlist *)0) { 50751898Smckusick hp = adp->dp_hosts; 50851898Smckusick gotalldir = 0; 50951898Smckusick } 51051898Smckusick } 51151898Smckusick } 51251898Smckusick if (!xdr_bool(xdrsp, &false)) 51351898Smckusick return (1); 514*64903Smckusick if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 51551898Smckusick return (1); 51651898Smckusick } 51751898Smckusick return (0); 51851898Smckusick } 51951898Smckusick 52038460Smckusick #define LINESIZ 10240 52138460Smckusick char line[LINESIZ]; 52251898Smckusick FILE *exp_file; 52338460Smckusick 52438460Smckusick /* 52538460Smckusick * Get the export list 52638460Smckusick */ 52746709Sbostic void 52838460Smckusick get_exportlist() 52938460Smckusick { 53038460Smckusick register struct exportlist *ep, *ep2; 53151898Smckusick register struct grouplist *grp, *tgrp; 53251898Smckusick struct exportlist **epp; 53351898Smckusick struct dirlist *dirhead; 53451898Smckusick struct stat sb; 53552109Smckusick struct statfs fsb, *fsp; 53651898Smckusick struct hostent *hpe; 53751898Smckusick struct ucred anon; 53852109Smckusick struct ufs_args targs; 53953150Smckusick char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 54053150Smckusick int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 54138460Smckusick 54238460Smckusick /* 54338460Smckusick * First, get rid of the old list 54438460Smckusick */ 54551898Smckusick ep = exphead; 54651898Smckusick while (ep) { 54738460Smckusick ep2 = ep; 54838460Smckusick ep = ep->ex_next; 54944015Smckusick free_exp(ep2); 55038460Smckusick } 55151898Smckusick exphead = (struct exportlist *)0; 55238460Smckusick 55351898Smckusick grp = grphead; 55451898Smckusick while (grp) { 55551898Smckusick tgrp = grp; 55651898Smckusick grp = grp->gr_next; 55751898Smckusick free_grp(tgrp); 55851667Smckusick } 55951898Smckusick grphead = (struct grouplist *)0; 56051667Smckusick 56138460Smckusick /* 56252109Smckusick * And delete exports that are in the kernel for all local 56352109Smckusick * file systems. 56452109Smckusick * XXX: Should know how to handle all local exportable file systems 56552109Smckusick * instead of just MOUNT_UFS. 56652109Smckusick */ 56753214Smckusick num = getmntinfo(&fsp, MNT_NOWAIT); 56852109Smckusick for (i = 0; i < num; i++) { 56952109Smckusick if (fsp->f_type == MOUNT_UFS) { 57052109Smckusick targs.fspec = (char *)0; 57152109Smckusick targs.exflags = MNT_DELEXPORT; 57252109Smckusick if (mount(fsp->f_type, fsp->f_mntonname, 57352109Smckusick fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0) 57452109Smckusick syslog(LOG_ERR, "Can't del exports %s", 57552109Smckusick fsp->f_mntonname); 57652109Smckusick } 57752109Smckusick fsp++; 57852109Smckusick } 57952109Smckusick 58052109Smckusick /* 58138460Smckusick * Read in the exports file and build the list, calling 58251667Smckusick * mount() as we go along to push the export rules into the kernel. 58338460Smckusick */ 58451898Smckusick if ((exp_file = fopen(exname, "r")) == NULL) { 58538460Smckusick syslog(LOG_ERR, "Can't open %s", exname); 58638460Smckusick exit(2); 58738460Smckusick } 58851898Smckusick dirhead = (struct dirlist *)0; 58951898Smckusick while (get_line()) { 59051667Smckusick if (debug) 59151667Smckusick fprintf(stderr,"Got line %s\n",line); 59238460Smckusick cp = line; 59338460Smckusick nextfield(&cp, &endcp); 59451667Smckusick if (*cp == '#') 59551667Smckusick goto nextline; 59651898Smckusick 59751898Smckusick /* 59851898Smckusick * Set defaults. 59951898Smckusick */ 60051898Smckusick has_host = FALSE; 60151898Smckusick anon = def_anon; 60251667Smckusick exflags = MNT_EXPORTED; 60351898Smckusick got_nondir = 0; 60451898Smckusick opt_flags = 0; 60551898Smckusick ep = (struct exportlist *)0; 60644015Smckusick 60744015Smckusick /* 60844015Smckusick * Create new exports list entry 60944015Smckusick */ 61038460Smckusick len = endcp-cp; 61153150Smckusick tgrp = grp = get_grp(); 61251898Smckusick while (len > 0) { 61351898Smckusick if (len > RPCMNT_NAMELEN) { 61453150Smckusick getexp_err(ep, tgrp); 61551898Smckusick goto nextline; 61651667Smckusick } 61745271Smckusick if (*cp == '-') { 61851898Smckusick if (ep == (struct exportlist *)0) { 61953150Smckusick getexp_err(ep, tgrp); 62051898Smckusick goto nextline; 62151898Smckusick } 62251898Smckusick if (debug) 62351898Smckusick fprintf(stderr, "doing opt %s\n", cp); 62451898Smckusick got_nondir = 1; 62551898Smckusick if (do_opt(&cp, &endcp, ep, grp, &has_host, 62651898Smckusick &exflags, &anon)) { 62753150Smckusick getexp_err(ep, tgrp); 62851898Smckusick goto nextline; 62951898Smckusick } 63051898Smckusick } else if (*cp == '/') { 63151898Smckusick savedc = *endcp; 63251898Smckusick *endcp = '\0'; 63351898Smckusick if (stat(cp, &sb) >= 0 && 63451898Smckusick (sb.st_mode & S_IFMT) == S_IFDIR && 63551898Smckusick statfs(cp, &fsb) >= 0) { 63651898Smckusick if (got_nondir) { 63751898Smckusick syslog(LOG_ERR, "Dirs must be first"); 63853150Smckusick getexp_err(ep, tgrp); 63951898Smckusick goto nextline; 64051898Smckusick } 64151898Smckusick if (ep) { 64251898Smckusick if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 64351898Smckusick ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 64453150Smckusick getexp_err(ep, tgrp); 64551898Smckusick goto nextline; 64651898Smckusick } 64751667Smckusick } else { 64851898Smckusick /* 64951898Smckusick * See if this directory is already 65051898Smckusick * in the list. 65151898Smckusick */ 65251898Smckusick ep = ex_search(&fsb.f_fsid); 65351898Smckusick if (ep == (struct exportlist *)0) { 65451898Smckusick ep = get_exp(); 65551898Smckusick ep->ex_fs = fsb.f_fsid; 65651898Smckusick ep->ex_fsdir = (char *) 65751898Smckusick malloc(strlen(fsb.f_mntonname) + 1); 65851898Smckusick if (ep->ex_fsdir) 65951898Smckusick strcpy(ep->ex_fsdir, 66051898Smckusick fsb.f_mntonname); 66151898Smckusick else 66251898Smckusick out_of_mem(); 66351898Smckusick if (debug) 66451898Smckusick fprintf(stderr, 66551898Smckusick "Making new ep fs=0x%x,0x%x\n", 66651898Smckusick fsb.f_fsid.val[0], 66751898Smckusick fsb.f_fsid.val[1]); 66851898Smckusick } else if (debug) 66951898Smckusick fprintf(stderr, 67051898Smckusick "Found ep fs=0x%x,0x%x\n", 67151898Smckusick fsb.f_fsid.val[0], 67251898Smckusick fsb.f_fsid.val[1]); 67338460Smckusick } 67451898Smckusick 67551898Smckusick /* 67651898Smckusick * Add dirpath to export mount point. 67751898Smckusick */ 67851898Smckusick dirp = add_expdir(&dirhead, cp, len); 67951898Smckusick dirplen = len; 68051898Smckusick } else { 68153150Smckusick getexp_err(ep, tgrp); 68251898Smckusick goto nextline; 68351898Smckusick } 68451898Smckusick *endcp = savedc; 68551898Smckusick } else { 68651898Smckusick savedc = *endcp; 68751898Smckusick *endcp = '\0'; 68851898Smckusick got_nondir = 1; 68953150Smckusick if (ep == (struct exportlist *)0) { 69053150Smckusick getexp_err(ep, tgrp); 69151898Smckusick goto nextline; 69251898Smckusick } 69353150Smckusick 69453150Smckusick /* 69553150Smckusick * Get the host or netgroup. 69653150Smckusick */ 69753150Smckusick setnetgrent(cp); 69853150Smckusick netgrp = getnetgrent(&hst, &usr, &dom); 69953150Smckusick do { 70053150Smckusick if (has_host) { 70153150Smckusick grp->gr_next = get_grp(); 70253150Smckusick grp = grp->gr_next; 70353150Smckusick } 70453150Smckusick if (netgrp) { 70553150Smckusick if (get_host(hst, grp)) { 70653150Smckusick syslog(LOG_ERR, "Bad netgroup %s", cp); 70753150Smckusick getexp_err(ep, tgrp); 70853150Smckusick goto nextline; 70953150Smckusick } 71053150Smckusick } else if (get_host(cp, grp)) { 71153150Smckusick getexp_err(ep, tgrp); 71253150Smckusick goto nextline; 71353150Smckusick } 71453150Smckusick has_host = TRUE; 71553150Smckusick } while (netgrp && getnetgrent(&hst, &usr, &dom)); 71653150Smckusick endnetgrent(); 71751898Smckusick *endcp = savedc; 71838460Smckusick } 71938460Smckusick cp = endcp; 72038460Smckusick nextfield(&cp, &endcp); 72145271Smckusick len = endcp - cp; 72238460Smckusick } 72351898Smckusick if (check_options(dirhead)) { 72453150Smckusick getexp_err(ep, tgrp); 72551898Smckusick goto nextline; 72651898Smckusick } 72751898Smckusick if (!has_host) { 72851898Smckusick grp->gr_type = GT_HOST; 72951667Smckusick if (debug) 73051667Smckusick fprintf(stderr,"Adding a default entry\n"); 73151667Smckusick /* add a default group and make the grp list NULL */ 73251667Smckusick hpe = (struct hostent *)malloc(sizeof(struct hostent)); 73351898Smckusick if (hpe == (struct hostent *)0) 73451898Smckusick out_of_mem(); 73551898Smckusick hpe->h_name = "Default"; 73651667Smckusick hpe->h_addrtype = AF_INET; 73751667Smckusick hpe->h_length = sizeof (u_long); 73851712Smckusick hpe->h_addr_list = (char **)0; 73951898Smckusick grp->gr_ptr.gt_hostent = hpe; 74053150Smckusick 74153150Smckusick /* 74253150Smckusick * Don't allow a network export coincide with a list of 74353150Smckusick * host(s) on the same line. 74453150Smckusick */ 74553150Smckusick } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 74653150Smckusick getexp_err(ep, tgrp); 74753150Smckusick goto nextline; 74851667Smckusick } 74953150Smckusick 75053150Smckusick /* 75153150Smckusick * Loop through hosts, pushing the exports into the kernel. 75253150Smckusick * After loop, tgrp points to the start of the list and 75353150Smckusick * grp points to the last entry in the list. 75453150Smckusick */ 75553150Smckusick grp = tgrp; 75653150Smckusick do { 75753150Smckusick if (do_mount(ep, grp, exflags, &anon, dirp, 75851898Smckusick dirplen, &fsb)) { 75953150Smckusick getexp_err(ep, tgrp); 76051898Smckusick goto nextline; 76153150Smckusick } 76253150Smckusick } while (grp->gr_next && (grp = grp->gr_next)); 76351898Smckusick 76451898Smckusick /* 76551898Smckusick * Success. Update the data structures. 76651898Smckusick */ 76751898Smckusick if (has_host) { 76853150Smckusick hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS)); 76951898Smckusick grp->gr_next = grphead; 77053150Smckusick grphead = tgrp; 77151898Smckusick } else { 77251898Smckusick hang_dirp(dirhead, (struct grouplist *)0, ep, 77353150Smckusick (opt_flags & OP_ALLDIRS)); 77451898Smckusick free_grp(grp); 77551898Smckusick } 77651898Smckusick dirhead = (struct dirlist *)0; 77751898Smckusick if ((ep->ex_flag & EX_LINKED) == 0) { 77851898Smckusick ep2 = exphead; 77951898Smckusick epp = &exphead; 78051898Smckusick 78151898Smckusick /* 78251898Smckusick * Insert in the list in alphabetical order. 78351898Smckusick */ 78451898Smckusick while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 78551898Smckusick epp = &ep2->ex_next; 78651898Smckusick ep2 = ep2->ex_next; 78751898Smckusick } 78851898Smckusick if (ep2) 78951898Smckusick ep->ex_next = ep2; 79051898Smckusick *epp = ep; 79151898Smckusick ep->ex_flag |= EX_LINKED; 79251898Smckusick } 79351898Smckusick nextline: 79451898Smckusick if (dirhead) { 79551898Smckusick free_dir(dirhead); 79651898Smckusick dirhead = (struct dirlist *)0; 79751898Smckusick } 79851898Smckusick } 79951898Smckusick fclose(exp_file); 80051898Smckusick } 80151898Smckusick 80251898Smckusick /* 80351898Smckusick * Allocate an export list element 80451898Smckusick */ 80551898Smckusick struct exportlist * 80651898Smckusick get_exp() 80751898Smckusick { 80851898Smckusick register struct exportlist *ep; 80951898Smckusick 81051898Smckusick ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 81151898Smckusick if (ep == (struct exportlist *)0) 81251898Smckusick out_of_mem(); 81351898Smckusick bzero((caddr_t)ep, sizeof (struct exportlist)); 81451898Smckusick return (ep); 81551898Smckusick } 81651898Smckusick 81751898Smckusick /* 81851898Smckusick * Allocate a group list element 81951898Smckusick */ 82051898Smckusick struct grouplist * 82151898Smckusick get_grp() 82251898Smckusick { 82351898Smckusick register struct grouplist *gp; 82451898Smckusick 82551898Smckusick gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 82651898Smckusick if (gp == (struct grouplist *)0) 82751898Smckusick out_of_mem(); 82851898Smckusick bzero((caddr_t)gp, sizeof (struct grouplist)); 82951898Smckusick return (gp); 83051898Smckusick } 83151898Smckusick 83251898Smckusick /* 83351898Smckusick * Clean up upon an error in get_exportlist(). 83451898Smckusick */ 83551898Smckusick void 83651898Smckusick getexp_err(ep, grp) 83751898Smckusick struct exportlist *ep; 83851898Smckusick struct grouplist *grp; 83951898Smckusick { 84053150Smckusick struct grouplist *tgrp; 84151898Smckusick 84251898Smckusick syslog(LOG_ERR, "Bad exports list line %s", line); 84359017Smckusick if (ep && (ep->ex_flag & EX_LINKED) == 0) 84451898Smckusick free_exp(ep); 84553150Smckusick while (grp) { 84653150Smckusick tgrp = grp; 84753150Smckusick grp = grp->gr_next; 84853150Smckusick free_grp(tgrp); 84953150Smckusick } 85051898Smckusick } 85151898Smckusick 85251898Smckusick /* 85351898Smckusick * Search the export list for a matching fs. 85451898Smckusick */ 85551898Smckusick struct exportlist * 85651898Smckusick ex_search(fsid) 85752109Smckusick fsid_t *fsid; 85851898Smckusick { 85951898Smckusick register struct exportlist *ep; 86051898Smckusick 86151898Smckusick ep = exphead; 86251898Smckusick while (ep) { 86351898Smckusick if (ep->ex_fs.val[0] == fsid->val[0] && 86451898Smckusick ep->ex_fs.val[1] == fsid->val[1]) 86551898Smckusick return (ep); 86651898Smckusick ep = ep->ex_next; 86751898Smckusick } 86851898Smckusick return (ep); 86951898Smckusick } 87051898Smckusick 87151898Smckusick /* 87251898Smckusick * Add a directory path to the list. 87351898Smckusick */ 87451898Smckusick char * 87551898Smckusick add_expdir(dpp, cp, len) 87651898Smckusick struct dirlist **dpp; 87751898Smckusick char *cp; 87851898Smckusick int len; 87951898Smckusick { 88051898Smckusick register struct dirlist *dp; 88151898Smckusick 88251898Smckusick dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 88351898Smckusick dp->dp_left = *dpp; 88451898Smckusick dp->dp_right = (struct dirlist *)0; 88551898Smckusick dp->dp_flag = 0; 88651898Smckusick dp->dp_hosts = (struct hostlist *)0; 88751898Smckusick strcpy(dp->dp_dirp, cp); 88851898Smckusick *dpp = dp; 88951898Smckusick return (dp->dp_dirp); 89051898Smckusick } 89151898Smckusick 89251898Smckusick /* 89351898Smckusick * Hang the dir list element off the dirpath binary tree as required 89451898Smckusick * and update the entry for host. 89551898Smckusick */ 89651898Smckusick void 89751898Smckusick hang_dirp(dp, grp, ep, alldirs) 89851898Smckusick register struct dirlist *dp; 89951898Smckusick struct grouplist *grp; 90051898Smckusick struct exportlist *ep; 90151898Smckusick int alldirs; 90251898Smckusick { 90351898Smckusick register struct hostlist *hp; 90451898Smckusick struct dirlist *dp2; 90551898Smckusick 90651898Smckusick if (alldirs) { 90751898Smckusick if (ep->ex_defdir) 90851898Smckusick free((caddr_t)dp); 90951898Smckusick else 91051898Smckusick ep->ex_defdir = dp; 91155292Smckusick if (grp == (struct grouplist *)0) 91255292Smckusick ep->ex_defdir->dp_flag |= DP_DEFSET; 91355292Smckusick else while (grp) { 91451898Smckusick hp = get_ht(); 91551898Smckusick hp->ht_grp = grp; 91651898Smckusick hp->ht_next = ep->ex_defdir->dp_hosts; 91751898Smckusick ep->ex_defdir->dp_hosts = hp; 91855292Smckusick grp = grp->gr_next; 91955292Smckusick } 92051898Smckusick } else { 92153150Smckusick 92253150Smckusick /* 92353150Smckusick * Loop throught the directories adding them to the tree. 92453150Smckusick */ 92551898Smckusick while (dp) { 92651898Smckusick dp2 = dp->dp_left; 92753150Smckusick add_dlist(&ep->ex_dirl, dp, grp); 92851898Smckusick dp = dp2; 92951898Smckusick } 93051898Smckusick } 93151898Smckusick } 93251898Smckusick 93351898Smckusick /* 93451898Smckusick * Traverse the binary tree either updating a node that is already there 93551898Smckusick * for the new directory or adding the new node. 93651898Smckusick */ 93751898Smckusick void 93853150Smckusick add_dlist(dpp, newdp, grp) 93951898Smckusick struct dirlist **dpp; 94051898Smckusick struct dirlist *newdp; 94153150Smckusick register struct grouplist *grp; 94251898Smckusick { 94351898Smckusick register struct dirlist *dp; 94453150Smckusick register struct hostlist *hp; 94551898Smckusick int cmp; 94651898Smckusick 94751898Smckusick dp = *dpp; 94851898Smckusick if (dp) { 94951898Smckusick cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 95051898Smckusick if (cmp > 0) { 95153150Smckusick add_dlist(&dp->dp_left, newdp, grp); 95251898Smckusick return; 95351898Smckusick } else if (cmp < 0) { 95453150Smckusick add_dlist(&dp->dp_right, newdp, grp); 95551898Smckusick return; 95651898Smckusick } else 95751898Smckusick free((caddr_t)newdp); 95851898Smckusick } else { 95951898Smckusick dp = newdp; 96051898Smckusick dp->dp_left = (struct dirlist *)0; 96151898Smckusick *dpp = dp; 96251898Smckusick } 96353150Smckusick if (grp) { 96453150Smckusick 96553150Smckusick /* 96653150Smckusick * Hang all of the host(s) off of the directory point. 96753150Smckusick */ 96853150Smckusick do { 96953150Smckusick hp = get_ht(); 97053150Smckusick hp->ht_grp = grp; 97153150Smckusick hp->ht_next = dp->dp_hosts; 97253150Smckusick dp->dp_hosts = hp; 97353150Smckusick grp = grp->gr_next; 97453150Smckusick } while (grp); 97551898Smckusick } else 97651898Smckusick dp->dp_flag |= DP_DEFSET; 97751898Smckusick } 97851898Smckusick 97951898Smckusick /* 98051898Smckusick * Search for a dirpath on the export point. 98151898Smckusick */ 98251898Smckusick struct dirlist * 98351898Smckusick dirp_search(dp, dirpath) 98451898Smckusick register struct dirlist *dp; 98551898Smckusick char *dirpath; 98651898Smckusick { 98751898Smckusick register int cmp; 98851898Smckusick 98951898Smckusick if (dp) { 99051898Smckusick cmp = strcmp(dp->dp_dirp, dirpath); 99151898Smckusick if (cmp > 0) 99251898Smckusick return (dirp_search(dp->dp_left, dirpath)); 99351898Smckusick else if (cmp < 0) 99451898Smckusick return (dirp_search(dp->dp_right, dirpath)); 99551898Smckusick else 99651898Smckusick return (dp); 99751898Smckusick } 99851898Smckusick return (dp); 99951898Smckusick } 100051898Smckusick 100151898Smckusick /* 100251898Smckusick * Scan for a host match in a directory tree. 100351898Smckusick */ 100451898Smckusick chk_host(dp, saddr, defsetp) 100551898Smckusick struct dirlist *dp; 100651898Smckusick u_long saddr; 100751898Smckusick int *defsetp; 100851898Smckusick { 100951898Smckusick register struct hostlist *hp; 101051898Smckusick register struct grouplist *grp; 101151898Smckusick register u_long **addrp; 101251898Smckusick 101351898Smckusick if (dp) { 101451898Smckusick if (dp->dp_flag & DP_DEFSET) 101551898Smckusick *defsetp = 1; 101651898Smckusick hp = dp->dp_hosts; 101751898Smckusick while (hp) { 101851898Smckusick grp = hp->ht_grp; 101951898Smckusick switch (grp->gr_type) { 102051898Smckusick case GT_HOST: 102151898Smckusick addrp = (u_long **) 102251898Smckusick grp->gr_ptr.gt_hostent->h_addr_list; 102351898Smckusick while (*addrp) { 102451898Smckusick if (**addrp == saddr) 102551898Smckusick return (1); 102651898Smckusick addrp++; 102751898Smckusick } 102851898Smckusick break; 102951898Smckusick case GT_NET: 103051898Smckusick if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 103151898Smckusick grp->gr_ptr.gt_net.nt_net) 103251898Smckusick return (1); 103351898Smckusick break; 103451898Smckusick }; 103551898Smckusick hp = hp->ht_next; 103651898Smckusick } 103751898Smckusick } 103851898Smckusick return (0); 103951898Smckusick } 104051898Smckusick 104151898Smckusick /* 104251898Smckusick * Scan tree for a host that matches the address. 104351898Smckusick */ 104451898Smckusick scan_tree(dp, saddr) 104551898Smckusick register struct dirlist *dp; 104651898Smckusick u_long saddr; 104751898Smckusick { 104851898Smckusick int defset; 104951898Smckusick 105051898Smckusick if (dp) { 105151898Smckusick if (scan_tree(dp->dp_left, saddr)) 105251898Smckusick return (1); 105351898Smckusick if (chk_host(dp, saddr, &defset)) 105451898Smckusick return (1); 105551898Smckusick if (scan_tree(dp->dp_right, saddr)) 105651898Smckusick return (1); 105751898Smckusick } 105851898Smckusick return (0); 105951898Smckusick } 106051898Smckusick 106151898Smckusick /* 106251898Smckusick * Traverse the dirlist tree and free it up. 106351898Smckusick */ 106451898Smckusick void 106551898Smckusick free_dir(dp) 106651898Smckusick register struct dirlist *dp; 106751898Smckusick { 106851898Smckusick 106951898Smckusick if (dp) { 107051898Smckusick free_dir(dp->dp_left); 107151898Smckusick free_dir(dp->dp_right); 107251898Smckusick free_host(dp->dp_hosts); 107351898Smckusick free((caddr_t)dp); 107451898Smckusick } 107551898Smckusick } 107651898Smckusick 107751898Smckusick /* 107851898Smckusick * Parse the option string and update fields. 107951898Smckusick * Option arguments may either be -<option>=<value> or 108051898Smckusick * -<option> <value> 108151898Smckusick */ 108251898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 108351898Smckusick char **cpp, **endcpp; 108451898Smckusick struct exportlist *ep; 108551898Smckusick struct grouplist *grp; 108651898Smckusick int *has_hostp; 108751898Smckusick int *exflagsp; 108851898Smckusick struct ucred *cr; 108951898Smckusick { 109051898Smckusick register char *cpoptarg, *cpoptend; 109151898Smckusick char *cp, *endcp, *cpopt, savedc, savedc2; 109251898Smckusick int allflag, usedarg; 109351898Smckusick 109451898Smckusick cpopt = *cpp; 109551898Smckusick cpopt++; 109651898Smckusick cp = *endcpp; 109751898Smckusick savedc = *cp; 109851898Smckusick *cp = '\0'; 109951898Smckusick while (cpopt && *cpopt) { 110051898Smckusick allflag = 1; 110151898Smckusick usedarg = -2; 110251898Smckusick if (cpoptend = index(cpopt, ',')) { 110351898Smckusick *cpoptend++ = '\0'; 110451898Smckusick if (cpoptarg = index(cpopt, '=')) 110551898Smckusick *cpoptarg++ = '\0'; 110651898Smckusick } else { 110751898Smckusick if (cpoptarg = index(cpopt, '=')) 110851898Smckusick *cpoptarg++ = '\0'; 110951898Smckusick else { 111051898Smckusick *cp = savedc; 111151898Smckusick nextfield(&cp, &endcp); 111251898Smckusick **endcpp = '\0'; 111351898Smckusick if (endcp > cp && *cp != '-') { 111451898Smckusick cpoptarg = cp; 111551898Smckusick savedc2 = *endcp; 111651898Smckusick *endcp = '\0'; 111751898Smckusick usedarg = 0; 111851667Smckusick } 111951667Smckusick } 112051667Smckusick } 112151898Smckusick if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 112251898Smckusick *exflagsp |= MNT_EXRDONLY; 112351898Smckusick } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 112451898Smckusick !(allflag = strcmp(cpopt, "mapall")) || 112551898Smckusick !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 112651898Smckusick usedarg++; 112751898Smckusick parsecred(cpoptarg, cr); 112851898Smckusick if (allflag == 0) { 112951898Smckusick *exflagsp |= MNT_EXPORTANON; 113051898Smckusick opt_flags |= OP_MAPALL; 113151898Smckusick } else 113251898Smckusick opt_flags |= OP_MAPROOT; 113351898Smckusick } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 113451898Smckusick *exflagsp |= MNT_EXKERB; 113551898Smckusick opt_flags |= OP_KERB; 113653150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "mask") || 113753150Smckusick !strcmp(cpopt, "m"))) { 113851898Smckusick if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 113951898Smckusick syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 114051898Smckusick return (1); 114151898Smckusick } 114251898Smckusick usedarg++; 114351898Smckusick opt_flags |= OP_MASK; 114453150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "network") || 114553150Smckusick !strcmp(cpopt, "n"))) { 114651898Smckusick if (grp->gr_type != GT_NULL) { 114751898Smckusick syslog(LOG_ERR, "Network/host conflict"); 114851898Smckusick return (1); 114951898Smckusick } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 115051898Smckusick syslog(LOG_ERR, "Bad net: %s", cpoptarg); 115151898Smckusick return (1); 115251898Smckusick } 115351898Smckusick grp->gr_type = GT_NET; 115451898Smckusick *has_hostp = 1; 115551898Smckusick usedarg++; 115651898Smckusick opt_flags |= OP_NET; 115751898Smckusick } else if (!strcmp(cpopt, "alldirs")) { 115851898Smckusick opt_flags |= OP_ALLDIRS; 115951898Smckusick #ifdef ISO 116051898Smckusick } else if (cpoptarg && !strcmp(cpopt, "iso")) { 116151898Smckusick if (get_isoaddr(cpoptarg, grp)) { 116251898Smckusick syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 116351898Smckusick return (1); 116451898Smckusick } 116551898Smckusick *has_hostp = 1; 116651898Smckusick usedarg++; 116751898Smckusick opt_flags |= OP_ISO; 116851898Smckusick #endif /* ISO */ 116951898Smckusick } else { 117051898Smckusick syslog(LOG_ERR, "Bad opt %s", cpopt); 117151898Smckusick return (1); 117251667Smckusick } 117351898Smckusick if (usedarg >= 0) { 117451898Smckusick *endcp = savedc2; 117551898Smckusick **endcpp = savedc; 117651898Smckusick if (usedarg > 0) { 117751898Smckusick *cpp = cp; 117851898Smckusick *endcpp = endcp; 117951898Smckusick } 118051898Smckusick return (0); 118151898Smckusick } 118251898Smckusick cpopt = cpoptend; 118351667Smckusick } 118451898Smckusick **endcpp = savedc; 118551898Smckusick return (0); 118651898Smckusick } 118751898Smckusick 118851898Smckusick /* 118951898Smckusick * Translate a character string to the corresponding list of network 119051898Smckusick * addresses for a hostname. 119151898Smckusick */ 119251898Smckusick get_host(cp, grp) 119351898Smckusick char *cp; 119451898Smckusick register struct grouplist *grp; 119551898Smckusick { 119651898Smckusick register struct hostent *hp, *nhp; 119751898Smckusick register char **addrp, **naddrp; 119851898Smckusick struct hostent t_host; 119951898Smckusick int i; 120051898Smckusick u_long saddr; 120151898Smckusick char *aptr[2]; 120251898Smckusick 120351898Smckusick if (grp->gr_type != GT_NULL) 120451898Smckusick return (1); 120551898Smckusick if ((hp = gethostbyname(cp)) == NULL) { 120651898Smckusick if (isdigit(*cp)) { 120751898Smckusick saddr = inet_addr(cp); 120851898Smckusick if (saddr == -1) { 120951898Smckusick syslog(LOG_ERR, "Inet_addr failed"); 121051898Smckusick return (1); 121151898Smckusick } 121251898Smckusick if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 121351898Smckusick AF_INET)) == NULL) { 121451898Smckusick hp = &t_host; 121551898Smckusick hp->h_name = cp; 121651898Smckusick hp->h_addrtype = AF_INET; 121751898Smckusick hp->h_length = sizeof (u_long); 121851898Smckusick hp->h_addr_list = aptr; 121951898Smckusick aptr[0] = (char *)&saddr; 122051898Smckusick aptr[1] = (char *)0; 122151898Smckusick } 122251898Smckusick } else { 122351898Smckusick syslog(LOG_ERR, "Gethostbyname failed"); 122451898Smckusick return (1); 122551898Smckusick } 122651898Smckusick } 122751898Smckusick grp->gr_type = GT_HOST; 122851898Smckusick nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 122951898Smckusick malloc(sizeof(struct hostent)); 123051898Smckusick if (nhp == (struct hostent *)0) 123151898Smckusick out_of_mem(); 123251898Smckusick bcopy((caddr_t)hp, (caddr_t)nhp, 123351898Smckusick sizeof(struct hostent)); 123451898Smckusick i = strlen(hp->h_name)+1; 123551898Smckusick nhp->h_name = (char *)malloc(i); 123651898Smckusick if (nhp->h_name == (char *)0) 123751898Smckusick out_of_mem(); 123851898Smckusick bcopy(hp->h_name, nhp->h_name, i); 123951898Smckusick addrp = hp->h_addr_list; 124051898Smckusick i = 1; 124151898Smckusick while (*addrp++) 124251898Smckusick i++; 124351898Smckusick naddrp = nhp->h_addr_list = (char **) 124451898Smckusick malloc(i*sizeof(char *)); 124551898Smckusick if (naddrp == (char **)0) 124651898Smckusick out_of_mem(); 124751898Smckusick addrp = hp->h_addr_list; 124851898Smckusick while (*addrp) { 124951898Smckusick *naddrp = (char *) 125051898Smckusick malloc(hp->h_length); 125151898Smckusick if (*naddrp == (char *)0) 125251898Smckusick out_of_mem(); 125351898Smckusick bcopy(*addrp, *naddrp, 125451898Smckusick hp->h_length); 125551898Smckusick addrp++; 125651898Smckusick naddrp++; 125751898Smckusick } 125851898Smckusick *naddrp = (char *)0; 125953150Smckusick if (debug) 126053150Smckusick fprintf(stderr, "got host %s\n", hp->h_name); 126151898Smckusick return (0); 126251898Smckusick } 126351898Smckusick 126451898Smckusick /* 126551898Smckusick * Free up an exports list component 126651898Smckusick */ 126751898Smckusick void 126851898Smckusick free_exp(ep) 126951898Smckusick register struct exportlist *ep; 127051898Smckusick { 127151898Smckusick 127251898Smckusick if (ep->ex_defdir) { 127351898Smckusick free_host(ep->ex_defdir->dp_hosts); 127451898Smckusick free((caddr_t)ep->ex_defdir); 127551898Smckusick } 127651898Smckusick if (ep->ex_fsdir) 127751898Smckusick free(ep->ex_fsdir); 127851898Smckusick free_dir(ep->ex_dirl); 127951898Smckusick free((caddr_t)ep); 128051898Smckusick } 128151898Smckusick 128251898Smckusick /* 128351898Smckusick * Free hosts. 128451898Smckusick */ 128551898Smckusick void 128651898Smckusick free_host(hp) 128751898Smckusick register struct hostlist *hp; 128851898Smckusick { 128951898Smckusick register struct hostlist *hp2; 129051898Smckusick 129151898Smckusick while (hp) { 129251898Smckusick hp2 = hp; 129351898Smckusick hp = hp->ht_next; 129451898Smckusick free((caddr_t)hp2); 129551898Smckusick } 129651898Smckusick } 129751898Smckusick 129851898Smckusick struct hostlist * 129951898Smckusick get_ht() 130051898Smckusick { 130151898Smckusick register struct hostlist *hp; 130251898Smckusick 130351898Smckusick hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 130451898Smckusick if (hp == (struct hostlist *)0) 130551898Smckusick out_of_mem(); 130651898Smckusick hp->ht_next = (struct hostlist *)0; 130751898Smckusick return (hp); 130851898Smckusick } 130951898Smckusick 131051898Smckusick #ifdef ISO 131151898Smckusick /* 131251898Smckusick * Translate an iso address. 131351898Smckusick */ 131451898Smckusick get_isoaddr(cp, grp) 131551898Smckusick char *cp; 131651898Smckusick struct grouplist *grp; 131751898Smckusick { 131851898Smckusick struct iso_addr *isop; 131951898Smckusick struct sockaddr_iso *isoaddr; 132051898Smckusick 132151898Smckusick if (grp->gr_type != GT_NULL) 132251898Smckusick return (1); 132351898Smckusick if ((isop = iso_addr(cp)) == NULL) { 132451898Smckusick syslog(LOG_ERR, 132551898Smckusick "iso_addr failed, ignored"); 132651898Smckusick return (1); 132751898Smckusick } 132851898Smckusick isoaddr = (struct sockaddr_iso *) 132951898Smckusick malloc(sizeof (struct sockaddr_iso)); 133051898Smckusick if (isoaddr == (struct sockaddr_iso *)0) 133151898Smckusick out_of_mem(); 133251898Smckusick bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 133351898Smckusick bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 133451898Smckusick sizeof (struct iso_addr)); 133551898Smckusick isoaddr->siso_len = sizeof (struct sockaddr_iso); 133651898Smckusick isoaddr->siso_family = AF_ISO; 133751898Smckusick grp->gr_type = GT_ISO; 133851898Smckusick grp->gr_ptr.gt_isoaddr = isoaddr; 133951898Smckusick return (0); 134051898Smckusick } 134151898Smckusick #endif /* ISO */ 134251898Smckusick 134351898Smckusick /* 134451898Smckusick * Out of memory, fatal 134551898Smckusick */ 134651898Smckusick void 134751898Smckusick out_of_mem() 134851898Smckusick { 134951898Smckusick 135051898Smckusick syslog(LOG_ERR, "Out of memory"); 135151667Smckusick exit(2); 135251667Smckusick } 135351667Smckusick 135451898Smckusick /* 135551898Smckusick * Do the mount syscall with the update flag to push the export info into 135651898Smckusick * the kernel. 135751898Smckusick */ 135851898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 135951667Smckusick struct exportlist *ep; 136051667Smckusick struct grouplist *grp; 136151898Smckusick int exflags; 136251667Smckusick struct ucred *anoncrp; 136351898Smckusick char *dirp; 136451898Smckusick int dirplen; 136551898Smckusick struct statfs *fsb; 136651667Smckusick { 136751898Smckusick register char *cp = (char *)0; 136851667Smckusick register u_long **addrp; 136951898Smckusick int done; 137051898Smckusick char savedc; 137151898Smckusick struct sockaddr_in sin, imask; 137252109Smckusick struct ufs_args args; 137351898Smckusick u_long net; 137451667Smckusick 137551667Smckusick args.fspec = 0; 137651667Smckusick args.exflags = exflags; 137751667Smckusick args.anon = *anoncrp; 137855878Smckusick bzero((char *)&sin, sizeof(sin)); 137955878Smckusick bzero((char *)&imask, sizeof(imask)); 138051667Smckusick sin.sin_family = AF_INET; 138151667Smckusick sin.sin_len = sizeof(sin); 138251898Smckusick imask.sin_family = AF_INET; 138351898Smckusick imask.sin_len = sizeof(sin); 138451898Smckusick if (grp->gr_type == GT_HOST) 138551667Smckusick addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 138651898Smckusick else 138751898Smckusick addrp = (u_long **)0; 138851667Smckusick done = FALSE; 138951898Smckusick while (!done) { 139051898Smckusick switch (grp->gr_type) { 139151898Smckusick case GT_HOST: 1392*64903Smckusick if (addrp) { 139351712Smckusick sin.sin_addr.s_addr = **addrp; 1394*64903Smckusick args.slen = sizeof(sin); 1395*64903Smckusick } else 1396*64903Smckusick args.slen = 0; 139751667Smckusick args.saddr = (struct sockaddr *)&sin; 139851898Smckusick args.msklen = 0; 139951898Smckusick break; 140051898Smckusick case GT_NET: 140151898Smckusick if (grp->gr_ptr.gt_net.nt_mask) 140251898Smckusick imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 140351898Smckusick else { 140451898Smckusick net = ntohl(grp->gr_ptr.gt_net.nt_net); 140551898Smckusick if (IN_CLASSA(net)) 140651898Smckusick imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 140751898Smckusick else if (IN_CLASSB(net)) 140851898Smckusick imask.sin_addr.s_addr = 140951898Smckusick inet_addr("255.255.0.0"); 141051898Smckusick else 141151898Smckusick imask.sin_addr.s_addr = 141251898Smckusick inet_addr("255.255.255.0"); 141351898Smckusick grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 141451898Smckusick } 141551898Smckusick sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 141651898Smckusick args.saddr = (struct sockaddr *)&sin; 141751898Smckusick args.slen = sizeof (sin); 141851898Smckusick args.smask = (struct sockaddr *)&imask; 141951898Smckusick args.msklen = sizeof (imask); 142051898Smckusick break; 142151667Smckusick #ifdef ISO 142251898Smckusick case GT_ISO: 142351667Smckusick args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 142451667Smckusick args.slen = sizeof (struct sockaddr_iso); 142551898Smckusick args.msklen = 0; 142651898Smckusick break; 142751667Smckusick #endif /* ISO */ 142851898Smckusick default: 142951667Smckusick syslog(LOG_ERR, "Bad grouptype"); 143051898Smckusick if (cp) 143151898Smckusick *cp = savedc; 143251898Smckusick return (1); 143351898Smckusick }; 143452109Smckusick 143552109Smckusick /* 143652109Smckusick * XXX: 143752109Smckusick * Maybe I should just use the fsb->f_mntonname path instead 143852109Smckusick * of looping back up the dirp to the mount point?? 143952109Smckusick * Also, needs to know how to export all types of local 144052109Smckusick * exportable file systems and not just MOUNT_UFS. 144152109Smckusick */ 144252109Smckusick while (mount(fsb->f_type, dirp, 144352109Smckusick fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 144451898Smckusick if (cp) 144551898Smckusick *cp-- = savedc; 144651898Smckusick else 144751898Smckusick cp = dirp + dirplen - 1; 144851667Smckusick if (errno == EPERM) { 144951667Smckusick syslog(LOG_ERR, 145051898Smckusick "Can't change attributes for %s.\n", dirp); 145151898Smckusick return (1); 145251667Smckusick } 145351898Smckusick if (opt_flags & OP_ALLDIRS) { 145451898Smckusick syslog(LOG_ERR, "Not root dir"); 145551898Smckusick return (1); 145651898Smckusick } 145751667Smckusick /* back up over the last component */ 145851898Smckusick while (*cp == '/' && cp > dirp) 145951667Smckusick cp--; 146051898Smckusick while (*(cp - 1) != '/' && cp > dirp) 146151667Smckusick cp--; 146251898Smckusick if (cp == dirp) { 146351898Smckusick if (debug) 146451667Smckusick fprintf(stderr,"mnt unsucc\n"); 146551898Smckusick syslog(LOG_ERR, "Can't export %s", dirp); 146651898Smckusick return (1); 146751667Smckusick } 146851667Smckusick savedc = *cp; 146951667Smckusick *cp = '\0'; 147051667Smckusick } 147151898Smckusick if (addrp) { 147251667Smckusick ++addrp; 147351898Smckusick if (*addrp == (u_long *)0) 147451667Smckusick done = TRUE; 147551898Smckusick } else 147651898Smckusick done = TRUE; 147751898Smckusick } 147851898Smckusick if (cp) 147951898Smckusick *cp = savedc; 148051898Smckusick return (0); 148151898Smckusick } 148251898Smckusick 148351898Smckusick /* 148451898Smckusick * Translate a net address. 148551898Smckusick */ 148651898Smckusick get_net(cp, net, maskflg) 148751898Smckusick char *cp; 148851898Smckusick struct netmsk *net; 148951898Smckusick int maskflg; 149051898Smckusick { 149151898Smckusick register struct netent *np; 149251898Smckusick register long netaddr; 149351898Smckusick struct in_addr inetaddr, inetaddr2; 149451898Smckusick char *name; 149551898Smckusick 149651898Smckusick if (np = getnetbyname(cp)) 149751898Smckusick inetaddr = inet_makeaddr(np->n_net, 0); 149851898Smckusick else if (isdigit(*cp)) { 149951898Smckusick if ((netaddr = inet_network(cp)) == -1) 150051898Smckusick return (1); 150151898Smckusick inetaddr = inet_makeaddr(netaddr, 0); 150251898Smckusick /* 150351898Smckusick * Due to arbritrary subnet masks, you don't know how many 150451898Smckusick * bits to shift the address to make it into a network, 150551898Smckusick * however you do know how to make a network address into 150651898Smckusick * a host with host == 0 and then compare them. 150751898Smckusick * (What a pest) 150851898Smckusick */ 150951898Smckusick if (!maskflg) { 151051898Smckusick setnetent(0); 151151898Smckusick while (np = getnetent()) { 151251898Smckusick inetaddr2 = inet_makeaddr(np->n_net, 0); 151351898Smckusick if (inetaddr2.s_addr == inetaddr.s_addr) 151451898Smckusick break; 151551898Smckusick } 151651898Smckusick endnetent(); 151751667Smckusick } 151851898Smckusick } else 151951898Smckusick return (1); 152051898Smckusick if (maskflg) 152151898Smckusick net->nt_mask = inetaddr.s_addr; 152251898Smckusick else { 152351898Smckusick if (np) 152451898Smckusick name = np->n_name; 152551898Smckusick else 152651898Smckusick name = inet_ntoa(inetaddr); 152751898Smckusick net->nt_name = (char *)malloc(strlen(name) + 1); 152851898Smckusick if (net->nt_name == (char *)0) 152951898Smckusick out_of_mem(); 153051898Smckusick strcpy(net->nt_name, name); 153151898Smckusick net->nt_net = inetaddr.s_addr; 153238460Smckusick } 153351898Smckusick return (0); 153438460Smckusick } 153538460Smckusick 153638460Smckusick /* 153738460Smckusick * Parse out the next white space separated field 153838460Smckusick */ 153951667Smckusick void 154038460Smckusick nextfield(cp, endcp) 154138460Smckusick char **cp; 154238460Smckusick char **endcp; 154338460Smckusick { 154438460Smckusick register char *p; 154538460Smckusick 154638460Smckusick p = *cp; 154738460Smckusick while (*p == ' ' || *p == '\t') 154838460Smckusick p++; 154951898Smckusick if (*p == '\n' || *p == '\0') 155038460Smckusick *cp = *endcp = p; 155151898Smckusick else { 155251898Smckusick *cp = p++; 155351898Smckusick while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 155451898Smckusick p++; 155551898Smckusick *endcp = p; 155638460Smckusick } 155738460Smckusick } 155839681Smckusick 155939681Smckusick /* 156051898Smckusick * Get an exports file line. Skip over blank lines and handle line 156151898Smckusick * continuations. 156239681Smckusick */ 156351898Smckusick get_line() 156439681Smckusick { 156551898Smckusick register char *p, *cp; 156651898Smckusick register int len; 156751898Smckusick int totlen, cont_line; 156839681Smckusick 156951898Smckusick /* 157051898Smckusick * Loop around ignoring blank lines and getting all continuation lines. 157151898Smckusick */ 157251898Smckusick p = line; 157351898Smckusick totlen = 0; 157451898Smckusick do { 157551898Smckusick if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 157651898Smckusick return (0); 157751898Smckusick len = strlen(p); 157851898Smckusick cp = p + len - 1; 157951898Smckusick cont_line = 0; 158051898Smckusick while (cp >= p && 158151898Smckusick (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 158251898Smckusick if (*cp == '\\') 158351898Smckusick cont_line = 1; 158451898Smckusick cp--; 158551898Smckusick len--; 158651898Smckusick } 158751898Smckusick *++cp = '\0'; 158851898Smckusick if (len > 0) { 158951898Smckusick totlen += len; 159051898Smckusick if (totlen >= LINESIZ) { 159151898Smckusick syslog(LOG_ERR, "Exports line too long"); 159251898Smckusick exit(2); 159351898Smckusick } 159451898Smckusick p = cp; 159551898Smckusick } 159651898Smckusick } while (totlen == 0 || cont_line); 159751898Smckusick return (1); 159844015Smckusick } 159944015Smckusick 160051667Smckusick /* 160151667Smckusick * Parse a description of a credential. 160251667Smckusick */ 160351667Smckusick parsecred(namelist, cr) 160451667Smckusick char *namelist; 160551667Smckusick register struct ucred *cr; 160651667Smckusick { 160751667Smckusick register char *name; 160851667Smckusick register int cnt; 160951667Smckusick char *names; 161051667Smckusick struct passwd *pw; 161151667Smckusick struct group *gr; 161251667Smckusick int ngroups, groups[NGROUPS + 1]; 161351667Smckusick 161451667Smckusick /* 161551667Smckusick * Set up the unpriviledged user. 161651667Smckusick */ 161751667Smckusick cr->cr_ref = 1; 161851667Smckusick cr->cr_uid = -2; 161951667Smckusick cr->cr_groups[0] = -2; 162051667Smckusick cr->cr_ngroups = 1; 162151667Smckusick /* 162251667Smckusick * Get the user's password table entry. 162351667Smckusick */ 162451667Smckusick names = strsep(&namelist, " \t\n"); 162551667Smckusick name = strsep(&names, ":"); 162651667Smckusick if (isdigit(*name) || *name == '-') 162751667Smckusick pw = getpwuid(atoi(name)); 162851667Smckusick else 162951667Smckusick pw = getpwnam(name); 163051667Smckusick /* 163151667Smckusick * Credentials specified as those of a user. 163251667Smckusick */ 163351667Smckusick if (names == NULL) { 163451667Smckusick if (pw == NULL) { 163551667Smckusick syslog(LOG_ERR, "Unknown user: %s\n", name); 163651667Smckusick return; 163751667Smckusick } 163851667Smckusick cr->cr_uid = pw->pw_uid; 163951667Smckusick ngroups = NGROUPS + 1; 164051667Smckusick if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 164151667Smckusick syslog(LOG_ERR, "Too many groups\n"); 164251667Smckusick /* 164351667Smckusick * Convert from int's to gid_t's and compress out duplicate 164451667Smckusick */ 164551667Smckusick cr->cr_ngroups = ngroups - 1; 164651667Smckusick cr->cr_groups[0] = groups[0]; 164751667Smckusick for (cnt = 2; cnt < ngroups; cnt++) 164851667Smckusick cr->cr_groups[cnt - 1] = groups[cnt]; 164951667Smckusick return; 165051667Smckusick } 165151667Smckusick /* 165251667Smckusick * Explicit credential specified as a colon separated list: 165351667Smckusick * uid:gid:gid:... 165451667Smckusick */ 165551667Smckusick if (pw != NULL) 165651667Smckusick cr->cr_uid = pw->pw_uid; 165751667Smckusick else if (isdigit(*name) || *name == '-') 165851667Smckusick cr->cr_uid = atoi(name); 165951667Smckusick else { 166051667Smckusick syslog(LOG_ERR, "Unknown user: %s\n", name); 166151667Smckusick return; 166251667Smckusick } 166351667Smckusick cr->cr_ngroups = 0; 166451667Smckusick while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 166551667Smckusick name = strsep(&names, ":"); 166651667Smckusick if (isdigit(*name) || *name == '-') { 166751667Smckusick cr->cr_groups[cr->cr_ngroups++] = atoi(name); 166851667Smckusick } else { 166951667Smckusick if ((gr = getgrnam(name)) == NULL) { 167051667Smckusick syslog(LOG_ERR, "Unknown group: %s\n", name); 167151667Smckusick continue; 167251667Smckusick } 167351667Smckusick cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 167451667Smckusick } 167551667Smckusick } 167651667Smckusick if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 167751667Smckusick syslog(LOG_ERR, "Too many groups\n"); 167851667Smckusick } 167951667Smckusick 168044015Smckusick #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 168144015Smckusick /* 168244015Smckusick * Routines that maintain the remote mounttab 168344015Smckusick */ 168451667Smckusick void 168551667Smckusick get_mountlist() 168644015Smckusick { 168744015Smckusick register struct mountlist *mlp, **mlpp; 168844015Smckusick register char *eos, *dirp; 168944015Smckusick int len; 169044015Smckusick char str[STRSIZ]; 169144015Smckusick FILE *mlfile; 169244015Smckusick 169351712Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 169451667Smckusick syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 169544015Smckusick return; 169644015Smckusick } 169744015Smckusick mlpp = &mlhead; 169844015Smckusick while (fgets(str, STRSIZ, mlfile) != NULL) { 169944015Smckusick if ((dirp = index(str, '\t')) == NULL && 170044015Smckusick (dirp = index(str, ' ')) == NULL) 170144015Smckusick continue; 170244015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 170344015Smckusick len = dirp-str; 170444015Smckusick if (len > RPCMNT_NAMELEN) 170544015Smckusick len = RPCMNT_NAMELEN; 170644015Smckusick bcopy(str, mlp->ml_host, len); 170744015Smckusick mlp->ml_host[len] = '\0'; 170844015Smckusick while (*dirp == '\t' || *dirp == ' ') 170944015Smckusick dirp++; 171044015Smckusick if ((eos = index(dirp, '\t')) == NULL && 171144015Smckusick (eos = index(dirp, ' ')) == NULL && 171244015Smckusick (eos = index(dirp, '\n')) == NULL) 171344015Smckusick len = strlen(dirp); 171444015Smckusick else 171544015Smckusick len = eos-dirp; 171644015Smckusick if (len > RPCMNT_PATHLEN) 171744015Smckusick len = RPCMNT_PATHLEN; 171844015Smckusick bcopy(dirp, mlp->ml_dirp, len); 171944015Smckusick mlp->ml_dirp[len] = '\0'; 172044015Smckusick mlp->ml_next = (struct mountlist *)0; 172144015Smckusick *mlpp = mlp; 172244015Smckusick mlpp = &mlp->ml_next; 172344015Smckusick } 172444015Smckusick fclose(mlfile); 172544015Smckusick } 172644015Smckusick 172751667Smckusick void 172851667Smckusick del_mlist(hostp, dirp) 172944015Smckusick register char *hostp, *dirp; 173044015Smckusick { 173144015Smckusick register struct mountlist *mlp, **mlpp; 173251712Smckusick struct mountlist *mlp2; 173344015Smckusick FILE *mlfile; 173444015Smckusick int fnd = 0; 173544015Smckusick 173644015Smckusick mlpp = &mlhead; 173744015Smckusick mlp = mlhead; 173844015Smckusick while (mlp) { 173944015Smckusick if (!strcmp(mlp->ml_host, hostp) && 174044015Smckusick (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 174144015Smckusick fnd = 1; 174251712Smckusick mlp2 = mlp; 174351712Smckusick *mlpp = mlp = mlp->ml_next; 174451712Smckusick free((caddr_t)mlp2); 174551712Smckusick } else { 174651712Smckusick mlpp = &mlp->ml_next; 174751712Smckusick mlp = mlp->ml_next; 174839681Smckusick } 174939681Smckusick } 175044015Smckusick if (fnd) { 175144015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 175251898Smckusick syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 175344015Smckusick return; 175444015Smckusick } 175544015Smckusick mlp = mlhead; 175644015Smckusick while (mlp) { 175744015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 175844015Smckusick mlp = mlp->ml_next; 175944015Smckusick } 176044015Smckusick fclose(mlfile); 176144015Smckusick } 176239681Smckusick } 176344015Smckusick 176451667Smckusick void 176551667Smckusick add_mlist(hostp, dirp) 176644015Smckusick register char *hostp, *dirp; 176744015Smckusick { 176844015Smckusick register struct mountlist *mlp, **mlpp; 176944015Smckusick FILE *mlfile; 177044015Smckusick 177144015Smckusick mlpp = &mlhead; 177244015Smckusick mlp = mlhead; 177344015Smckusick while (mlp) { 177444015Smckusick if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 177544015Smckusick return; 177644015Smckusick mlpp = &mlp->ml_next; 177744015Smckusick mlp = mlp->ml_next; 177844015Smckusick } 177944015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 178044015Smckusick strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 178144015Smckusick mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 178244015Smckusick strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 178344015Smckusick mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 178444015Smckusick mlp->ml_next = (struct mountlist *)0; 178544015Smckusick *mlpp = mlp; 178644015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 178751898Smckusick syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 178844015Smckusick return; 178944015Smckusick } 179044015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 179144015Smckusick fclose(mlfile); 179244015Smckusick } 179344015Smckusick 179444015Smckusick /* 179544015Smckusick * This function is called via. SIGTERM when the system is going down. 179644015Smckusick * It sends a broadcast RPCMNT_UMNTALL. 179744015Smckusick */ 179846709Sbostic void 179944015Smckusick send_umntall() 180044015Smckusick { 180144015Smckusick (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 180244015Smckusick xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 180351667Smckusick exit(0); 180444015Smckusick } 180544015Smckusick 180644015Smckusick umntall_each(resultsp, raddr) 180744015Smckusick caddr_t resultsp; 180844015Smckusick struct sockaddr_in *raddr; 180944015Smckusick { 181044015Smckusick return (1); 181144015Smckusick } 181244015Smckusick 181344015Smckusick /* 181451667Smckusick * Free up a group list. 181551667Smckusick */ 181651667Smckusick void 181751667Smckusick free_grp(grp) 181851667Smckusick register struct grouplist *grp; 181951667Smckusick { 182051667Smckusick register char **addrp; 182151667Smckusick 182251898Smckusick if (grp->gr_type == GT_HOST) { 182351712Smckusick if (grp->gr_ptr.gt_hostent->h_name) { 182451712Smckusick addrp = grp->gr_ptr.gt_hostent->h_addr_list; 182551712Smckusick while (addrp && *addrp) 182651712Smckusick free(*addrp++); 182751712Smckusick free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 182851712Smckusick free(grp->gr_ptr.gt_hostent->h_name); 182951712Smckusick } 183051667Smckusick free((caddr_t)grp->gr_ptr.gt_hostent); 183151898Smckusick } else if (grp->gr_type == GT_NET) { 183251898Smckusick if (grp->gr_ptr.gt_net.nt_name) 183351898Smckusick free(grp->gr_ptr.gt_net.nt_name); 183451667Smckusick } 183551667Smckusick #ifdef ISO 183651898Smckusick else if (grp->gr_type == GT_ISO) 183751667Smckusick free((caddr_t)grp->gr_ptr.gt_isoaddr); 183851667Smckusick #endif 183951667Smckusick free((caddr_t)grp); 184051667Smckusick } 184151667Smckusick 184251667Smckusick /* 184351667Smckusick * char *realpath(const char *path, char resolved_path[MAXPATHLEN]) 184451667Smckusick * 184551667Smckusick * find the real name of path, by removing all ".", ".." 184651667Smckusick * and symlink components. 184751667Smckusick * 184851667Smckusick * Jan-Simon Pendry, September 1991. 184951667Smckusick */ 185051667Smckusick char * 185151667Smckusick realpath(path, resolved) 185251667Smckusick char *path; 185351667Smckusick char resolved[MAXPATHLEN]; 185451667Smckusick { 185551667Smckusick int d = open(".", O_RDONLY); 185651667Smckusick int rootd = 0; 185751667Smckusick char *p, *q; 185851667Smckusick struct stat stb; 185951667Smckusick char wbuf[MAXPATHLEN]; 186051667Smckusick 186151667Smckusick strcpy(resolved, path); 186251667Smckusick 186351667Smckusick if (d < 0) 186451667Smckusick return 0; 186551667Smckusick 186651667Smckusick loop:; 186751667Smckusick q = strrchr(resolved, '/'); 186851667Smckusick if (q) { 186951667Smckusick p = q + 1; 187051667Smckusick if (q == resolved) 187151667Smckusick q = "/"; 187251667Smckusick else { 187351667Smckusick do 187451667Smckusick --q; 187551667Smckusick while (q > resolved && *q == '/'); 187651667Smckusick q[1] = '\0'; 187751667Smckusick q = resolved; 187851667Smckusick } 187951667Smckusick if (chdir(q) < 0) 188051667Smckusick goto out; 188151667Smckusick } else 188251667Smckusick p = resolved; 188351667Smckusick 188451667Smckusick if (lstat(p, &stb) == 0) { 188551667Smckusick if (S_ISLNK(stb.st_mode)) { 188651667Smckusick int n = readlink(p, resolved, MAXPATHLEN); 188751667Smckusick if (n < 0) 188851667Smckusick goto out; 188951667Smckusick resolved[n] = '\0'; 189051667Smckusick goto loop; 189151667Smckusick } 189251667Smckusick if (S_ISDIR(stb.st_mode)) { 189351667Smckusick if (chdir(p) < 0) 189451667Smckusick goto out; 189551667Smckusick p = ""; 189651667Smckusick } 189751667Smckusick } 189851667Smckusick 189951667Smckusick strcpy(wbuf, p); 190051667Smckusick if (getcwd(resolved, MAXPATHLEN) == 0) 190151667Smckusick goto out; 190251667Smckusick if (resolved[0] == '/' && resolved[1] == '\0') 190351667Smckusick rootd = 1; 190451667Smckusick 190551667Smckusick if (*wbuf) { 190651667Smckusick if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) { 190751667Smckusick errno = ENAMETOOLONG; 190851667Smckusick goto out; 190951667Smckusick } 191051667Smckusick if (rootd == 0) 191151667Smckusick strcat(resolved, "/"); 191251667Smckusick strcat(resolved, wbuf); 191351667Smckusick } 191451667Smckusick 191551667Smckusick if (fchdir(d) < 0) 191651667Smckusick goto out; 191751667Smckusick (void) close(d); 191851667Smckusick 191951667Smckusick return resolved; 192051667Smckusick 192151667Smckusick out:; 192251667Smckusick (void) close(d); 192351667Smckusick return 0; 192451667Smckusick } 192551711Smckusick 192651711Smckusick #ifdef DEBUG 192751711Smckusick void 192851711Smckusick SYSLOG(int pri, const char *fmt, ...) 192951711Smckusick { 193051711Smckusick va_list ap; 193151711Smckusick 193251711Smckusick va_start(ap, fmt); 193351711Smckusick vfprintf(stderr, fmt, ap); 193451711Smckusick va_end(ap); 193551711Smckusick } 193651711Smckusick #endif /* DEBUG */ 193751898Smckusick 193851898Smckusick /* 193951898Smckusick * Check options for consistency. 194051898Smckusick */ 194151898Smckusick check_options(dp) 194251898Smckusick struct dirlist *dp; 194351898Smckusick { 194451898Smckusick 194551898Smckusick if (dp == (struct dirlist *)0) 194651898Smckusick return (1); 194751898Smckusick if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 194851898Smckusick (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 194951898Smckusick (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 195051898Smckusick syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 195151898Smckusick return (1); 195251898Smckusick } 195351898Smckusick if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 195451898Smckusick syslog(LOG_ERR, "-mask requires -net"); 195551898Smckusick return (1); 195651898Smckusick } 195751898Smckusick if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 195851898Smckusick syslog(LOG_ERR, "-net and -iso mutually exclusive"); 195951898Smckusick return (1); 196051898Smckusick } 196151898Smckusick if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 196251898Smckusick syslog(LOG_ERR, "-alldir has multiple directories"); 196351898Smckusick return (1); 196451898Smckusick } 196551898Smckusick return (0); 196651898Smckusick } 1967