138460Smckusick /* 238460Smckusick * Copyright (c) 1989 The Regents of the University of California. 338460Smckusick * 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 1238460Smckusick char copyright[] = 1338460Smckusick "@(#) Copyright (c) 1989 Regents of the University of California.\n\ 1438460Smckusick All rights reserved.\n"; 1538460Smckusick #endif not lint 1638460Smckusick 1738460Smckusick #ifndef lint 18*52109Smckusick static char sccsid[] = "@(#)mountd.c 5.20 (Berkeley) 01/06/92"; 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> 36*52109Smckusick #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" 4738460Smckusick 4838460Smckusick /* 4938460Smckusick * Structures for keeping the mount list and export list 5038460Smckusick */ 5138460Smckusick struct mountlist { 5244015Smckusick struct mountlist *ml_next; 5338460Smckusick char ml_host[RPCMNT_NAMELEN+1]; 5438460Smckusick char ml_dirp[RPCMNT_PATHLEN+1]; 5538460Smckusick }; 5638460Smckusick 5751898Smckusick struct dirlist { 5851898Smckusick struct dirlist *dp_left; 5951898Smckusick struct dirlist *dp_right; 6051898Smckusick int dp_flag; 6151898Smckusick struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 6251898Smckusick char dp_dirp[1]; /* Actually malloc'd to size of dir */ 6351898Smckusick }; 6451898Smckusick /* dp_flag bits */ 6551898Smckusick #define DP_DEFSET 0x1 6651898Smckusick 6738460Smckusick struct exportlist { 6838460Smckusick struct exportlist *ex_next; 6951898Smckusick struct dirlist *ex_dirl; 7051898Smckusick struct dirlist *ex_defdir; 7151898Smckusick int ex_flag; 7251898Smckusick fsid_t ex_fs; 7351898Smckusick char *ex_fsdir; 7438460Smckusick }; 7551898Smckusick /* ex_flag bits */ 76*52109Smckusick #define EX_LINKED 0x1 7738460Smckusick 7851898Smckusick struct netmsk { 7951898Smckusick u_long nt_net; 8051898Smckusick u_long nt_mask; 8151898Smckusick char *nt_name; 8251898Smckusick }; 8351898Smckusick 8451667Smckusick union grouptypes { 8551667Smckusick struct hostent *gt_hostent; 8651898Smckusick struct netmsk gt_net; 8751667Smckusick #ifdef ISO 8851667Smckusick struct sockaddr_iso *gt_isoaddr; 8951667Smckusick #endif 9051667Smckusick }; 9151667Smckusick 9238460Smckusick struct grouplist { 9351898Smckusick int gr_type; 9451667Smckusick union grouptypes gr_ptr; 9538460Smckusick struct grouplist *gr_next; 9638460Smckusick }; 9751898Smckusick /* Group types */ 9851898Smckusick #define GT_NULL 0x0 9951898Smckusick #define GT_HOST 0x1 10051898Smckusick #define GT_NET 0x2 10151898Smckusick #define GT_ISO 0x4 10238460Smckusick 10351898Smckusick struct hostlist { 10451898Smckusick struct grouplist *ht_grp; 10551898Smckusick struct hostlist *ht_next; 10651667Smckusick }; 10751667Smckusick 10838460Smckusick /* Global defs */ 10946709Sbostic int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist(); 11051898Smckusick void get_exportlist(), send_umntall(), nextfield(), out_of_mem(); 11151667Smckusick void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp(); 11251898Smckusick void getexp_err(), hang_dirp(), add_dlist(), free_dir(), free_host(); 11351898Smckusick struct exportlist *ex_search(), *get_exp(); 11451898Smckusick struct grouplist *get_grp(); 11551898Smckusick char *realpath(), *add_expdir(); 11651898Smckusick struct in_addr inet_makeaddr(); 11751898Smckusick char *inet_ntoa(); 11851898Smckusick struct dirlist *dirp_search(); 11951898Smckusick struct hostlist *get_ht(); 12051667Smckusick #ifdef ISO 12151667Smckusick struct iso_addr *iso_addr(); 12251667Smckusick #endif 12351898Smckusick struct exportlist *exphead; 12444015Smckusick struct mountlist *mlhead; 12551898Smckusick struct grouplist *grphead; 12638460Smckusick char exname[MAXPATHLEN]; 12751667Smckusick struct ucred def_anon = { 12851667Smckusick (u_short) 1, 12951667Smckusick (uid_t) -2, 13051667Smckusick 1, 13151667Smckusick (gid_t) -2, 13251667Smckusick }; 13344015Smckusick int root_only = 1; 13451898Smckusick int opt_flags; 13551898Smckusick /* Bits for above */ 13651898Smckusick #define OP_MAPROOT 0x01 13751898Smckusick #define OP_MAPALL 0x02 13851898Smckusick #define OP_KERB 0x04 13951898Smckusick #define OP_MASK 0x08 14051898Smckusick #define OP_NET 0x10 14151898Smckusick #define OP_ISO 0x20 14251898Smckusick #define OP_ALLDIRS 0x40 14351898Smckusick 14438460Smckusick extern int errno; 14538460Smckusick #ifdef DEBUG 14638460Smckusick int debug = 1; 14751711Smckusick void SYSLOG __P((int, const char *, ...)); 14851711Smckusick #define syslog SYSLOG 14938460Smckusick #else 15038460Smckusick int debug = 0; 15138460Smckusick #endif 15238460Smckusick 15338460Smckusick /* 15438460Smckusick * Mountd server for NFS mount protocol as described in: 15539681Smckusick * NFS: Network File System Protocol Specification, RFC1094, Appendix A 15644015Smckusick * The optional arguments are the exports file name 15739681Smckusick * default: _PATH_EXPORTS 15844015Smckusick * and "-n" to allow nonroot mount. 15938460Smckusick */ 16038460Smckusick main(argc, argv) 16138460Smckusick int argc; 16244015Smckusick char **argv; 16338460Smckusick { 16438460Smckusick SVCXPRT *transp; 16544015Smckusick int c; 16644015Smckusick extern int optind; 16744015Smckusick extern char *optarg; 16838460Smckusick 16944015Smckusick while ((c = getopt(argc, argv, "n")) != EOF) 17044015Smckusick switch (c) { 17144015Smckusick case 'n': 17244015Smckusick root_only = 0; 17344015Smckusick break; 17444015Smckusick default: 17544015Smckusick fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); 17644015Smckusick exit(1); 17744015Smckusick }; 17844015Smckusick argc -= optind; 17944015Smckusick argv += optind; 18051898Smckusick grphead = (struct grouplist *)0; 18151898Smckusick exphead = (struct exportlist *)0; 18244015Smckusick mlhead = (struct mountlist *)0; 18344015Smckusick if (argc == 1) { 18444015Smckusick strncpy(exname, *argv, MAXPATHLEN-1); 18544015Smckusick exname[MAXPATHLEN-1] = '\0'; 18644015Smckusick } else 18744015Smckusick strcpy(exname, _PATH_EXPORTS); 18844338Smckusick openlog("mountd:", LOG_PID, LOG_DAEMON); 18951667Smckusick if (debug) 19051667Smckusick fprintf(stderr,"Getting export list.\n"); 19144015Smckusick get_exportlist(); 19251667Smckusick if (debug) 19351667Smckusick fprintf(stderr,"Getting mount list.\n"); 19444015Smckusick get_mountlist(); 19551667Smckusick if (debug) 19651667Smckusick fprintf(stderr,"Here we go.\n"); 19738460Smckusick if (debug == 0) { 19844690Skarels daemon(0, 0); 19938460Smckusick signal(SIGINT, SIG_IGN); 20038460Smckusick signal(SIGQUIT, SIG_IGN); 20138460Smckusick } 20238460Smckusick signal(SIGHUP, get_exportlist); 20344015Smckusick signal(SIGTERM, send_umntall); 20440494Smckusick { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 20540494Smckusick if (pidfile != NULL) { 20640494Smckusick fprintf(pidfile, "%d\n", getpid()); 20740494Smckusick fclose(pidfile); 20840494Smckusick } 20940494Smckusick } 21038460Smckusick if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { 21138460Smckusick syslog(LOG_ERR, "Can't create socket"); 21238460Smckusick exit(1); 21338460Smckusick } 21438460Smckusick pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 21551667Smckusick if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 21651667Smckusick IPPROTO_UDP)) { 21738460Smckusick syslog(LOG_ERR, "Can't register mount"); 21838460Smckusick exit(1); 21938460Smckusick } 22038460Smckusick svc_run(); 22138460Smckusick syslog(LOG_ERR, "Mountd died"); 22244690Skarels exit(1); 22338460Smckusick } 22438460Smckusick 22538460Smckusick /* 22638460Smckusick * The mount rpc service 22738460Smckusick */ 22838460Smckusick mntsrv(rqstp, transp) 22938460Smckusick register struct svc_req *rqstp; 23038460Smckusick register SVCXPRT *transp; 23138460Smckusick { 23238460Smckusick register struct exportlist *ep; 23351898Smckusick register struct dirlist *dp; 23438460Smckusick nfsv2fh_t nfh; 23538460Smckusick struct authunix_parms *ucr; 23638460Smckusick struct stat stb; 23751898Smckusick struct statfs fsb; 23838460Smckusick struct hostent *hp; 23939681Smckusick u_long saddr; 24051667Smckusick char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; 24151898Smckusick int bad = ENOENT, omask, defset; 24239681Smckusick uid_t uid = -2; 24338460Smckusick 24438460Smckusick /* Get authorization */ 24538460Smckusick switch (rqstp->rq_cred.oa_flavor) { 24638460Smckusick case AUTH_UNIX: 24738460Smckusick ucr = (struct authunix_parms *)rqstp->rq_clntcred; 24839681Smckusick uid = ucr->aup_uid; 24939681Smckusick break; 25038460Smckusick case AUTH_NULL: 25138460Smckusick default: 25239681Smckusick break; 25338460Smckusick } 25438460Smckusick 25539681Smckusick saddr = transp->xp_raddr.sin_addr.s_addr; 25639681Smckusick hp = (struct hostent *)0; 25738460Smckusick switch (rqstp->rq_proc) { 25839681Smckusick case NULLPROC: 25939681Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 26039681Smckusick syslog(LOG_ERR, "Can't send reply"); 26139681Smckusick return; 26238460Smckusick case RPCMNT_MOUNT: 26351667Smckusick if ((uid != 0 && root_only) || uid == -2) { 26439681Smckusick svcerr_weakauth(transp); 26539681Smckusick return; 26639681Smckusick } 26751667Smckusick if (!svc_getargs(transp, xdr_dir, rpcpath)) { 26838460Smckusick svcerr_decode(transp); 26938460Smckusick return; 27038460Smckusick } 27138460Smckusick 27251667Smckusick /* 27351667Smckusick * Get the real pathname and make sure it is a directory 27451667Smckusick * that exists. 27551667Smckusick */ 27651898Smckusick if (realpath(rpcpath, dirpath) == 0 || 27751898Smckusick stat(dirpath, &stb) < 0 || 27851898Smckusick (stb.st_mode & S_IFMT) != S_IFDIR || 27951898Smckusick statfs(dirpath, &fsb) < 0) { 28051667Smckusick chdir("/"); /* Just in case realpath doesn't */ 28151667Smckusick if (debug) 28251898Smckusick fprintf(stderr, "stat failed on %s\n", dirpath); 28338460Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 28438460Smckusick syslog(LOG_ERR, "Can't send reply"); 28538460Smckusick return; 28638460Smckusick } 28738460Smckusick 28838460Smckusick /* Check in the exports list */ 28938460Smckusick omask = sigblock(sigmask(SIGHUP)); 29051898Smckusick ep = ex_search(&fsb.f_fsid); 29151898Smckusick defset = 0; 29251898Smckusick if (ep && (chk_host(ep->ex_defdir, saddr, &defset) || 29351898Smckusick ((dp = dirp_search(ep->ex_dirl, dirpath)) && 29451898Smckusick chk_host(dp, saddr, &defset)) || 29551898Smckusick (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 29651898Smckusick scan_tree(ep->ex_dirl, saddr) == 0))) { 29751667Smckusick /* Get the file handle */ 29851667Smckusick bzero((caddr_t)&nfh, sizeof(nfh)); 29951667Smckusick if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { 30051667Smckusick bad = errno; 30151898Smckusick syslog(LOG_ERR, "Can't get fh for %s", dirpath); 30251667Smckusick if (!svc_sendreply(transp, xdr_long, 30351667Smckusick (caddr_t)&bad)) 30451667Smckusick syslog(LOG_ERR, "Can't send reply"); 30551667Smckusick sigsetmask(omask); 30651667Smckusick return; 30751667Smckusick } 30851667Smckusick if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) 30938460Smckusick syslog(LOG_ERR, "Can't send reply"); 31051667Smckusick if (hp == NULL) 31151667Smckusick hp = gethostbyaddr((caddr_t)&saddr, 31251667Smckusick sizeof(saddr), AF_INET); 31351667Smckusick if (hp) 31451667Smckusick add_mlist(hp->h_name, dirpath); 31551667Smckusick else 31651667Smckusick add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 31751667Smckusick dirpath); 31851667Smckusick if (debug) 31951667Smckusick fprintf(stderr,"Mount successfull.\n"); 32051898Smckusick } else { 32151898Smckusick bad = EACCES; 32251898Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 32351898Smckusick syslog(LOG_ERR, "Can't send reply"); 32438460Smckusick } 32551667Smckusick sigsetmask(omask); 32638460Smckusick return; 32738460Smckusick case RPCMNT_DUMP: 32838460Smckusick if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0)) 32938460Smckusick syslog(LOG_ERR, "Can't send reply"); 33038460Smckusick return; 33138460Smckusick case RPCMNT_UMOUNT: 33251667Smckusick if ((uid != 0 && root_only) || uid == -2) { 33339681Smckusick svcerr_weakauth(transp); 33439681Smckusick return; 33539681Smckusick } 33638460Smckusick if (!svc_getargs(transp, xdr_dir, dirpath)) { 33738460Smckusick svcerr_decode(transp); 33838460Smckusick return; 33938460Smckusick } 34038460Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 34138460Smckusick syslog(LOG_ERR, "Can't send reply"); 34244015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 34344015Smckusick if (hp) 34444015Smckusick del_mlist(hp->h_name, dirpath); 34551667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 34638460Smckusick return; 34738460Smckusick case RPCMNT_UMNTALL: 34851667Smckusick if ((uid != 0 && root_only) || uid == -2) { 34939681Smckusick svcerr_weakauth(transp); 35039681Smckusick return; 35139681Smckusick } 35238460Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 35338460Smckusick syslog(LOG_ERR, "Can't send reply"); 35444015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 35544015Smckusick if (hp) 35644015Smckusick del_mlist(hp->h_name, (char *)0); 35751667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)0); 35838460Smckusick return; 35938460Smckusick case RPCMNT_EXPORT: 36038460Smckusick if (!svc_sendreply(transp, xdr_explist, (caddr_t)0)) 36138460Smckusick syslog(LOG_ERR, "Can't send reply"); 36238460Smckusick return; 36338460Smckusick default: 36438460Smckusick svcerr_noproc(transp); 36538460Smckusick return; 36638460Smckusick } 36738460Smckusick } 36838460Smckusick 36938460Smckusick /* 37038460Smckusick * Xdr conversion for a dirpath string 37138460Smckusick */ 37238460Smckusick xdr_dir(xdrsp, dirp) 37338460Smckusick XDR *xdrsp; 37438460Smckusick char *dirp; 37538460Smckusick { 37638460Smckusick return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 37738460Smckusick } 37838460Smckusick 37938460Smckusick /* 38038460Smckusick * Xdr routine to generate fhstatus 38138460Smckusick */ 38238460Smckusick xdr_fhs(xdrsp, nfh) 38338460Smckusick XDR *xdrsp; 38438460Smckusick nfsv2fh_t *nfh; 38538460Smckusick { 38638460Smckusick int ok = 0; 38738460Smckusick 38838460Smckusick if (!xdr_long(xdrsp, &ok)) 38938460Smckusick return (0); 39038460Smckusick return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); 39138460Smckusick } 39238460Smckusick 39338460Smckusick xdr_mlist(xdrsp, cp) 39438460Smckusick XDR *xdrsp; 39538460Smckusick caddr_t cp; 39638460Smckusick { 39744015Smckusick register struct mountlist *mlp; 39838460Smckusick int true = 1; 39938460Smckusick int false = 0; 40038460Smckusick char *strp; 40138460Smckusick 40244015Smckusick mlp = mlhead; 40344015Smckusick while (mlp) { 40444015Smckusick if (!xdr_bool(xdrsp, &true)) 40544015Smckusick return (0); 40644015Smckusick strp = &mlp->ml_host[0]; 40744015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 40844015Smckusick return (0); 40944015Smckusick strp = &mlp->ml_dirp[0]; 41044015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 41144015Smckusick return (0); 41244015Smckusick mlp = mlp->ml_next; 41338460Smckusick } 41438460Smckusick if (!xdr_bool(xdrsp, &false)) 41538460Smckusick return (0); 41638460Smckusick return (1); 41738460Smckusick } 41838460Smckusick 41938460Smckusick /* 42038460Smckusick * Xdr conversion for export list 42138460Smckusick */ 42238460Smckusick xdr_explist(xdrsp, cp) 42338460Smckusick XDR *xdrsp; 42438460Smckusick caddr_t cp; 42538460Smckusick { 42638460Smckusick register struct exportlist *ep; 42738460Smckusick int false = 0; 42838460Smckusick int omask; 42938460Smckusick 43038460Smckusick omask = sigblock(sigmask(SIGHUP)); 43151898Smckusick ep = exphead; 43251898Smckusick while (ep) { 43351898Smckusick if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir)) 43438460Smckusick goto errout; 43538460Smckusick ep = ep->ex_next; 43638460Smckusick } 43738460Smckusick sigsetmask(omask); 43838460Smckusick if (!xdr_bool(xdrsp, &false)) 43938460Smckusick return (0); 44038460Smckusick return (1); 44138460Smckusick errout: 44238460Smckusick sigsetmask(omask); 44338460Smckusick return (0); 44438460Smckusick } 44538460Smckusick 44651898Smckusick /* 44751898Smckusick * Called from xdr_explist() to traverse the tree and export the 44851898Smckusick * directory paths. 44951898Smckusick */ 45051898Smckusick put_exlist(dp, xdrsp, adp) 45151898Smckusick register struct dirlist *dp; 45251898Smckusick XDR *xdrsp; 45351898Smckusick struct dirlist *adp; 45451898Smckusick { 45551898Smckusick register struct grouplist *grp; 45651898Smckusick register struct hostlist *hp; 45751898Smckusick struct in_addr inaddr; 45851898Smckusick int true = 1; 45951898Smckusick int false = 0; 46051898Smckusick int gotalldir = 0; 46151898Smckusick char *strp; 46251898Smckusick 46351898Smckusick if (dp) { 46451898Smckusick if (put_exlist(dp->dp_left, xdrsp, adp)) 46551898Smckusick return (1); 46651898Smckusick if (!xdr_bool(xdrsp, &true)) 46751898Smckusick return (1); 46851898Smckusick strp = dp->dp_dirp; 46951898Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 47051898Smckusick return (1); 47151898Smckusick if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) 47251898Smckusick gotalldir = 1; 47351898Smckusick if ((dp->dp_flag & DP_DEFSET) == 0 && 47451898Smckusick (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 47551898Smckusick hp = dp->dp_hosts; 47651898Smckusick while (hp) { 47751898Smckusick grp = hp->ht_grp; 47851898Smckusick if (grp->gr_type == GT_HOST) { 47951898Smckusick if (!xdr_bool(xdrsp, &true)) 48051898Smckusick return (1); 48151898Smckusick strp = grp->gr_ptr.gt_hostent->h_name; 48251898Smckusick if (!xdr_string(xdrsp, &strp, 48351898Smckusick RPCMNT_NAMELEN)) 48451898Smckusick return (1); 48551898Smckusick } else if (grp->gr_type == GT_NET) { 48651898Smckusick if (!xdr_bool(xdrsp, &true)) 48751898Smckusick return (1); 48851898Smckusick strp = grp->gr_ptr.gt_net.nt_name; 48951898Smckusick if (!xdr_string(xdrsp, &strp, 49051898Smckusick RPCMNT_NAMELEN)) 49151898Smckusick return (1); 49251898Smckusick } 49351898Smckusick hp = hp->ht_next; 49451898Smckusick if (gotalldir && hp == (struct hostlist *)0) { 49551898Smckusick hp = adp->dp_hosts; 49651898Smckusick gotalldir = 0; 49751898Smckusick } 49851898Smckusick } 49951898Smckusick } 50051898Smckusick if (!xdr_bool(xdrsp, &false)) 50151898Smckusick return (1); 50251898Smckusick if (put_exlist(dp->dp_right, xdrsp, adp)) 50351898Smckusick return (1); 50451898Smckusick } 50551898Smckusick return (0); 50651898Smckusick } 50751898Smckusick 50838460Smckusick #define LINESIZ 10240 50938460Smckusick char line[LINESIZ]; 51051898Smckusick FILE *exp_file; 51138460Smckusick 51238460Smckusick /* 51338460Smckusick * Get the export list 51438460Smckusick */ 51546709Sbostic void 51638460Smckusick get_exportlist() 51738460Smckusick { 51838460Smckusick register struct exportlist *ep, *ep2; 51951898Smckusick register struct grouplist *grp, *tgrp; 52051898Smckusick struct exportlist **epp; 52151898Smckusick struct dirlist *dirhead; 52251898Smckusick struct stat sb; 523*52109Smckusick struct statfs fsb, *fsp; 52451898Smckusick struct hostent *hpe; 52551898Smckusick struct ucred anon; 526*52109Smckusick struct ufs_args targs; 52751898Smckusick char *cp, *endcp, *dirp; 52839681Smckusick char savedc; 529*52109Smckusick int len, has_host, exflags, got_nondir, dirplen, num, i; 53038460Smckusick 53138460Smckusick /* 53238460Smckusick * First, get rid of the old list 53338460Smckusick */ 53451898Smckusick ep = exphead; 53551898Smckusick while (ep) { 53638460Smckusick ep2 = ep; 53738460Smckusick ep = ep->ex_next; 53844015Smckusick free_exp(ep2); 53938460Smckusick } 54051898Smckusick exphead = (struct exportlist *)0; 54138460Smckusick 54251898Smckusick grp = grphead; 54351898Smckusick while (grp) { 54451898Smckusick tgrp = grp; 54551898Smckusick grp = grp->gr_next; 54651898Smckusick free_grp(tgrp); 54751667Smckusick } 54851898Smckusick grphead = (struct grouplist *)0; 54951667Smckusick 55038460Smckusick /* 551*52109Smckusick * And delete exports that are in the kernel for all local 552*52109Smckusick * file systems. 553*52109Smckusick * XXX: Should know how to handle all local exportable file systems 554*52109Smckusick * instead of just MOUNT_UFS. 555*52109Smckusick */ 556*52109Smckusick num = getmntinfo(&fsp, MNT_WAIT); 557*52109Smckusick for (i = 0; i < num; i++) { 558*52109Smckusick if (fsp->f_type == MOUNT_UFS) { 559*52109Smckusick targs.fspec = (char *)0; 560*52109Smckusick targs.exflags = MNT_DELEXPORT; 561*52109Smckusick if (mount(fsp->f_type, fsp->f_mntonname, 562*52109Smckusick fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0) 563*52109Smckusick syslog(LOG_ERR, "Can't del exports %s", 564*52109Smckusick fsp->f_mntonname); 565*52109Smckusick } 566*52109Smckusick fsp++; 567*52109Smckusick } 568*52109Smckusick 569*52109Smckusick /* 57038460Smckusick * Read in the exports file and build the list, calling 57151667Smckusick * mount() as we go along to push the export rules into the kernel. 57238460Smckusick */ 57351898Smckusick if ((exp_file = fopen(exname, "r")) == NULL) { 57438460Smckusick syslog(LOG_ERR, "Can't open %s", exname); 57538460Smckusick exit(2); 57638460Smckusick } 57751898Smckusick dirhead = (struct dirlist *)0; 57851898Smckusick while (get_line()) { 57951667Smckusick if (debug) 58051667Smckusick fprintf(stderr,"Got line %s\n",line); 58138460Smckusick cp = line; 58238460Smckusick nextfield(&cp, &endcp); 58351667Smckusick if (*cp == '#') 58451667Smckusick goto nextline; 58551898Smckusick 58651898Smckusick /* 58751898Smckusick * Set defaults. 58851898Smckusick */ 58951898Smckusick has_host = FALSE; 59051898Smckusick anon = def_anon; 59151667Smckusick exflags = MNT_EXPORTED; 59251898Smckusick got_nondir = 0; 59351898Smckusick opt_flags = 0; 59451898Smckusick ep = (struct exportlist *)0; 59544015Smckusick 59644015Smckusick /* 59744015Smckusick * Create new exports list entry 59844015Smckusick */ 59938460Smckusick len = endcp-cp; 60051898Smckusick grp = get_grp(); 60151898Smckusick while (len > 0) { 60251898Smckusick if (len > RPCMNT_NAMELEN) { 60351898Smckusick getexp_err(ep, grp); 60451898Smckusick goto nextline; 60551667Smckusick } 60645271Smckusick if (*cp == '-') { 60751898Smckusick if (ep == (struct exportlist *)0) { 60851898Smckusick getexp_err(ep, grp); 60951898Smckusick goto nextline; 61051898Smckusick } 61151898Smckusick if (debug) 61251898Smckusick fprintf(stderr, "doing opt %s\n", cp); 61351898Smckusick got_nondir = 1; 61451898Smckusick if (do_opt(&cp, &endcp, ep, grp, &has_host, 61551898Smckusick &exflags, &anon)) { 61651898Smckusick getexp_err(ep, grp); 61751898Smckusick goto nextline; 61851898Smckusick } 61951898Smckusick } else if (*cp == '/') { 62051898Smckusick savedc = *endcp; 62151898Smckusick *endcp = '\0'; 62251898Smckusick if (stat(cp, &sb) >= 0 && 62351898Smckusick (sb.st_mode & S_IFMT) == S_IFDIR && 62451898Smckusick statfs(cp, &fsb) >= 0) { 62551898Smckusick if (got_nondir) { 62651898Smckusick syslog(LOG_ERR, "Dirs must be first"); 62751898Smckusick getexp_err(ep, grp); 62851898Smckusick goto nextline; 62951898Smckusick } 63051898Smckusick if (ep) { 63151898Smckusick if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 63251898Smckusick ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 63351898Smckusick getexp_err(ep, grp); 63451898Smckusick goto nextline; 63551898Smckusick } 63651667Smckusick } else { 63751898Smckusick /* 63851898Smckusick * See if this directory is already 63951898Smckusick * in the list. 64051898Smckusick */ 64151898Smckusick ep = ex_search(&fsb.f_fsid); 64251898Smckusick if (ep == (struct exportlist *)0) { 64351898Smckusick ep = get_exp(); 64451898Smckusick ep->ex_fs = fsb.f_fsid; 64551898Smckusick ep->ex_fsdir = (char *) 64651898Smckusick malloc(strlen(fsb.f_mntonname) + 1); 64751898Smckusick if (ep->ex_fsdir) 64851898Smckusick strcpy(ep->ex_fsdir, 64951898Smckusick fsb.f_mntonname); 65051898Smckusick else 65151898Smckusick out_of_mem(); 65251898Smckusick if (debug) 65351898Smckusick fprintf(stderr, 65451898Smckusick "Making new ep fs=0x%x,0x%x\n", 65551898Smckusick fsb.f_fsid.val[0], 65651898Smckusick fsb.f_fsid.val[1]); 65751898Smckusick } else if (debug) 65851898Smckusick fprintf(stderr, 65951898Smckusick "Found ep fs=0x%x,0x%x\n", 66051898Smckusick fsb.f_fsid.val[0], 66151898Smckusick fsb.f_fsid.val[1]); 66238460Smckusick } 66351898Smckusick 66451898Smckusick /* 66551898Smckusick * Add dirpath to export mount point. 66651898Smckusick */ 66751898Smckusick dirp = add_expdir(&dirhead, cp, len); 66851898Smckusick dirplen = len; 66951898Smckusick } else { 67051898Smckusick getexp_err(ep, grp); 67151898Smckusick goto nextline; 67251898Smckusick } 67351898Smckusick *endcp = savedc; 67451898Smckusick } else { 67551898Smckusick savedc = *endcp; 67651898Smckusick *endcp = '\0'; 67751898Smckusick got_nondir = 1; 67851898Smckusick if (ep == (struct exportlist *)0 || has_host) { 67951898Smckusick getexp_err(ep, grp); 68051898Smckusick goto nextline; 68151898Smckusick } 68251898Smckusick if (get_host(cp, grp)) { 68351898Smckusick getexp_err(ep, grp); 68451898Smckusick goto nextline; 68551898Smckusick } 68651898Smckusick has_host = TRUE; 68751898Smckusick *endcp = savedc; 68838460Smckusick } 68938460Smckusick cp = endcp; 69038460Smckusick nextfield(&cp, &endcp); 69145271Smckusick len = endcp - cp; 69238460Smckusick } 69351898Smckusick if (check_options(dirhead)) { 69451898Smckusick getexp_err(ep, grp); 69551898Smckusick goto nextline; 69651898Smckusick } 69751898Smckusick if (!has_host) { 69851898Smckusick grp->gr_type = GT_HOST; 69951667Smckusick if (debug) 70051667Smckusick fprintf(stderr,"Adding a default entry\n"); 70151667Smckusick /* add a default group and make the grp list NULL */ 70251667Smckusick hpe = (struct hostent *)malloc(sizeof(struct hostent)); 70351898Smckusick if (hpe == (struct hostent *)0) 70451898Smckusick out_of_mem(); 70551898Smckusick hpe->h_name = "Default"; 70651667Smckusick hpe->h_addrtype = AF_INET; 70751667Smckusick hpe->h_length = sizeof (u_long); 70851712Smckusick hpe->h_addr_list = (char **)0; 70951898Smckusick grp->gr_ptr.gt_hostent = hpe; 71051667Smckusick } 71151898Smckusick if (do_mount(ep, grp, exflags, &anon, dirp, 71251898Smckusick dirplen, &fsb)) { 71351898Smckusick getexp_err(ep, grp); 71451898Smckusick goto nextline; 71551898Smckusick } 71651898Smckusick 71751898Smckusick /* 71851898Smckusick * Success. Update the data structures. 71951898Smckusick */ 72051898Smckusick if (has_host) { 72151898Smckusick grp->gr_next = grphead; 72251898Smckusick grphead = grp; 72351898Smckusick hang_dirp(dirhead, grp, ep, (opt_flags & OP_ALLDIRS)); 72451898Smckusick } else { 72551898Smckusick hang_dirp(dirhead, (struct grouplist *)0, ep, 72651898Smckusick (opt_flags & OP_ALLDIRS)); 72751898Smckusick free_grp(grp); 72851898Smckusick } 72951898Smckusick dirhead = (struct dirlist *)0; 73051898Smckusick if ((ep->ex_flag & EX_LINKED) == 0) { 73151898Smckusick ep2 = exphead; 73251898Smckusick epp = &exphead; 73351898Smckusick 73451898Smckusick /* 73551898Smckusick * Insert in the list in alphabetical order. 73651898Smckusick */ 73751898Smckusick while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 73851898Smckusick epp = &ep2->ex_next; 73951898Smckusick ep2 = ep2->ex_next; 74051898Smckusick } 74151898Smckusick if (ep2) 74251898Smckusick ep->ex_next = ep2; 74351898Smckusick *epp = ep; 74451898Smckusick ep->ex_flag |= EX_LINKED; 74551898Smckusick } 74651898Smckusick nextline: 74751898Smckusick if (dirhead) { 74851898Smckusick free_dir(dirhead); 74951898Smckusick dirhead = (struct dirlist *)0; 75051898Smckusick } 75151898Smckusick } 75251898Smckusick fclose(exp_file); 75351898Smckusick } 75451898Smckusick 75551898Smckusick /* 75651898Smckusick * Allocate an export list element 75751898Smckusick */ 75851898Smckusick struct exportlist * 75951898Smckusick get_exp() 76051898Smckusick { 76151898Smckusick register struct exportlist *ep; 76251898Smckusick 76351898Smckusick ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 76451898Smckusick if (ep == (struct exportlist *)0) 76551898Smckusick out_of_mem(); 76651898Smckusick bzero((caddr_t)ep, sizeof (struct exportlist)); 76751898Smckusick return (ep); 76851898Smckusick } 76951898Smckusick 77051898Smckusick /* 77151898Smckusick * Allocate a group list element 77251898Smckusick */ 77351898Smckusick struct grouplist * 77451898Smckusick get_grp() 77551898Smckusick { 77651898Smckusick register struct grouplist *gp; 77751898Smckusick 77851898Smckusick gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 77951898Smckusick if (gp == (struct grouplist *)0) 78051898Smckusick out_of_mem(); 78151898Smckusick bzero((caddr_t)gp, sizeof (struct grouplist)); 78251898Smckusick return (gp); 78351898Smckusick } 78451898Smckusick 78551898Smckusick /* 78651898Smckusick * Clean up upon an error in get_exportlist(). 78751898Smckusick */ 78851898Smckusick void 78951898Smckusick getexp_err(ep, grp) 79051898Smckusick struct exportlist *ep; 79151898Smckusick struct grouplist *grp; 79251898Smckusick { 79351898Smckusick 79451898Smckusick syslog(LOG_ERR, "Bad exports list line %s", line); 79551898Smckusick if (ep && ep->ex_next == (struct exportlist *)0) 79651898Smckusick free_exp(ep); 79751898Smckusick if (grp && grp->gr_next == (struct grouplist *)0) 79851898Smckusick free_grp(grp); 79951898Smckusick } 80051898Smckusick 80151898Smckusick /* 80251898Smckusick * Search the export list for a matching fs. 80351898Smckusick */ 80451898Smckusick struct exportlist * 80551898Smckusick ex_search(fsid) 806*52109Smckusick fsid_t *fsid; 80751898Smckusick { 80851898Smckusick register struct exportlist *ep; 80951898Smckusick 81051898Smckusick ep = exphead; 81151898Smckusick while (ep) { 81251898Smckusick if (ep->ex_fs.val[0] == fsid->val[0] && 81351898Smckusick ep->ex_fs.val[1] == fsid->val[1]) 81451898Smckusick return (ep); 81551898Smckusick ep = ep->ex_next; 81651898Smckusick } 81751898Smckusick return (ep); 81851898Smckusick } 81951898Smckusick 82051898Smckusick /* 82151898Smckusick * Add a directory path to the list. 82251898Smckusick */ 82351898Smckusick char * 82451898Smckusick add_expdir(dpp, cp, len) 82551898Smckusick struct dirlist **dpp; 82651898Smckusick char *cp; 82751898Smckusick int len; 82851898Smckusick { 82951898Smckusick register struct dirlist *dp; 83051898Smckusick 83151898Smckusick dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 83251898Smckusick dp->dp_left = *dpp; 83351898Smckusick dp->dp_right = (struct dirlist *)0; 83451898Smckusick dp->dp_flag = 0; 83551898Smckusick dp->dp_hosts = (struct hostlist *)0; 83651898Smckusick strcpy(dp->dp_dirp, cp); 83751898Smckusick *dpp = dp; 83851898Smckusick return (dp->dp_dirp); 83951898Smckusick } 84051898Smckusick 84151898Smckusick /* 84251898Smckusick * Hang the dir list element off the dirpath binary tree as required 84351898Smckusick * and update the entry for host. 84451898Smckusick */ 84551898Smckusick void 84651898Smckusick hang_dirp(dp, grp, ep, alldirs) 84751898Smckusick register struct dirlist *dp; 84851898Smckusick struct grouplist *grp; 84951898Smckusick struct exportlist *ep; 85051898Smckusick int alldirs; 85151898Smckusick { 85251898Smckusick register struct hostlist *hp; 85351898Smckusick struct dirlist *dp2; 85451898Smckusick 85551898Smckusick if (alldirs) { 85651898Smckusick if (ep->ex_defdir) 85751898Smckusick free((caddr_t)dp); 85851898Smckusick else 85951898Smckusick ep->ex_defdir = dp; 86051898Smckusick if (grp) { 86151898Smckusick hp = get_ht(); 86251898Smckusick hp->ht_grp = grp; 86351898Smckusick hp->ht_next = ep->ex_defdir->dp_hosts; 86451898Smckusick ep->ex_defdir->dp_hosts = hp; 86551898Smckusick } else 86651898Smckusick ep->ex_defdir->dp_flag |= DP_DEFSET; 86751898Smckusick } else { 86851898Smckusick while (dp) { 86951898Smckusick if (grp) { 87051898Smckusick hp = get_ht(); 87151898Smckusick hp->ht_grp = grp; 87251898Smckusick } else 87351898Smckusick hp = (struct hostlist *)0; 87451898Smckusick dp2 = dp->dp_left; 87551898Smckusick add_dlist(&ep->ex_dirl, dp, hp); 87651898Smckusick dp = dp2; 87751898Smckusick } 87851898Smckusick } 87951898Smckusick } 88051898Smckusick 88151898Smckusick /* 88251898Smckusick * Traverse the binary tree either updating a node that is already there 88351898Smckusick * for the new directory or adding the new node. 88451898Smckusick */ 88551898Smckusick void 88651898Smckusick add_dlist(dpp, newdp, hp) 88751898Smckusick struct dirlist **dpp; 88851898Smckusick struct dirlist *newdp; 88951898Smckusick struct hostlist *hp; 89051898Smckusick { 89151898Smckusick register struct dirlist *dp; 89251898Smckusick int cmp; 89351898Smckusick 89451898Smckusick dp = *dpp; 89551898Smckusick if (dp) { 89651898Smckusick cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 89751898Smckusick if (cmp > 0) { 89851898Smckusick add_dlist(&dp->dp_left, newdp, hp); 89951898Smckusick return; 90051898Smckusick } else if (cmp < 0) { 90151898Smckusick add_dlist(&dp->dp_right, newdp, hp); 90251898Smckusick return; 90351898Smckusick } else 90451898Smckusick free((caddr_t)newdp); 90551898Smckusick } else { 90651898Smckusick dp = newdp; 90751898Smckusick dp->dp_left = (struct dirlist *)0; 90851898Smckusick *dpp = dp; 90951898Smckusick } 91051898Smckusick if (hp) { 91151898Smckusick hp->ht_next = dp->dp_hosts; 91251898Smckusick dp->dp_hosts = hp; 91351898Smckusick } else 91451898Smckusick dp->dp_flag |= DP_DEFSET; 91551898Smckusick } 91651898Smckusick 91751898Smckusick /* 91851898Smckusick * Search for a dirpath on the export point. 91951898Smckusick */ 92051898Smckusick struct dirlist * 92151898Smckusick dirp_search(dp, dirpath) 92251898Smckusick register struct dirlist *dp; 92351898Smckusick char *dirpath; 92451898Smckusick { 92551898Smckusick register int cmp; 92651898Smckusick 92751898Smckusick if (dp) { 92851898Smckusick cmp = strcmp(dp->dp_dirp, dirpath); 92951898Smckusick if (cmp > 0) 93051898Smckusick return (dirp_search(dp->dp_left, dirpath)); 93151898Smckusick else if (cmp < 0) 93251898Smckusick return (dirp_search(dp->dp_right, dirpath)); 93351898Smckusick else 93451898Smckusick return (dp); 93551898Smckusick } 93651898Smckusick return (dp); 93751898Smckusick } 93851898Smckusick 93951898Smckusick /* 94051898Smckusick * Scan for a host match in a directory tree. 94151898Smckusick */ 94251898Smckusick chk_host(dp, saddr, defsetp) 94351898Smckusick struct dirlist *dp; 94451898Smckusick u_long saddr; 94551898Smckusick int *defsetp; 94651898Smckusick { 94751898Smckusick register struct hostlist *hp; 94851898Smckusick register struct grouplist *grp; 94951898Smckusick register u_long **addrp; 95051898Smckusick 95151898Smckusick if (dp) { 95251898Smckusick if (dp->dp_flag & DP_DEFSET) 95351898Smckusick *defsetp = 1; 95451898Smckusick hp = dp->dp_hosts; 95551898Smckusick while (hp) { 95651898Smckusick grp = hp->ht_grp; 95751898Smckusick switch (grp->gr_type) { 95851898Smckusick case GT_HOST: 95951898Smckusick addrp = (u_long **) 96051898Smckusick grp->gr_ptr.gt_hostent->h_addr_list; 96151898Smckusick while (*addrp) { 96251898Smckusick if (**addrp == saddr) 96351898Smckusick return (1); 96451898Smckusick addrp++; 96551898Smckusick } 96651898Smckusick break; 96751898Smckusick case GT_NET: 96851898Smckusick if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 96951898Smckusick grp->gr_ptr.gt_net.nt_net) 97051898Smckusick return (1); 97151898Smckusick break; 97251898Smckusick }; 97351898Smckusick hp = hp->ht_next; 97451898Smckusick } 97551898Smckusick } 97651898Smckusick return (0); 97751898Smckusick } 97851898Smckusick 97951898Smckusick /* 98051898Smckusick * Scan tree for a host that matches the address. 98151898Smckusick */ 98251898Smckusick scan_tree(dp, saddr) 98351898Smckusick register struct dirlist *dp; 98451898Smckusick u_long saddr; 98551898Smckusick { 98651898Smckusick int defset; 98751898Smckusick 98851898Smckusick if (dp) { 98951898Smckusick if (scan_tree(dp->dp_left, saddr)) 99051898Smckusick return (1); 99151898Smckusick if (chk_host(dp, saddr, &defset)) 99251898Smckusick return (1); 99351898Smckusick if (scan_tree(dp->dp_right, saddr)) 99451898Smckusick return (1); 99551898Smckusick } 99651898Smckusick return (0); 99751898Smckusick } 99851898Smckusick 99951898Smckusick /* 100051898Smckusick * Traverse the dirlist tree and free it up. 100151898Smckusick */ 100251898Smckusick void 100351898Smckusick free_dir(dp) 100451898Smckusick register struct dirlist *dp; 100551898Smckusick { 100651898Smckusick 100751898Smckusick if (dp) { 100851898Smckusick free_dir(dp->dp_left); 100951898Smckusick free_dir(dp->dp_right); 101051898Smckusick free_host(dp->dp_hosts); 101151898Smckusick free((caddr_t)dp); 101251898Smckusick } 101351898Smckusick } 101451898Smckusick 101551898Smckusick /* 101651898Smckusick * Parse the option string and update fields. 101751898Smckusick * Option arguments may either be -<option>=<value> or 101851898Smckusick * -<option> <value> 101951898Smckusick */ 102051898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 102151898Smckusick char **cpp, **endcpp; 102251898Smckusick struct exportlist *ep; 102351898Smckusick struct grouplist *grp; 102451898Smckusick int *has_hostp; 102551898Smckusick int *exflagsp; 102651898Smckusick struct ucred *cr; 102751898Smckusick { 102851898Smckusick register char *cpoptarg, *cpoptend; 102951898Smckusick char *cp, *endcp, *cpopt, savedc, savedc2; 103051898Smckusick int allflag, usedarg; 103151898Smckusick 103251898Smckusick cpopt = *cpp; 103351898Smckusick cpopt++; 103451898Smckusick cp = *endcpp; 103551898Smckusick savedc = *cp; 103651898Smckusick *cp = '\0'; 103751898Smckusick while (cpopt && *cpopt) { 103851898Smckusick allflag = 1; 103951898Smckusick usedarg = -2; 104051898Smckusick if (cpoptend = index(cpopt, ',')) { 104151898Smckusick *cpoptend++ = '\0'; 104251898Smckusick if (cpoptarg = index(cpopt, '=')) 104351898Smckusick *cpoptarg++ = '\0'; 104451898Smckusick } else { 104551898Smckusick if (cpoptarg = index(cpopt, '=')) 104651898Smckusick *cpoptarg++ = '\0'; 104751898Smckusick else { 104851898Smckusick *cp = savedc; 104951898Smckusick nextfield(&cp, &endcp); 105051898Smckusick **endcpp = '\0'; 105151898Smckusick if (endcp > cp && *cp != '-') { 105251898Smckusick cpoptarg = cp; 105351898Smckusick savedc2 = *endcp; 105451898Smckusick *endcp = '\0'; 105551898Smckusick usedarg = 0; 105651667Smckusick } 105751667Smckusick } 105851667Smckusick } 105951898Smckusick if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 106051898Smckusick *exflagsp |= MNT_EXRDONLY; 106151898Smckusick } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 106251898Smckusick !(allflag = strcmp(cpopt, "mapall")) || 106351898Smckusick !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 106451898Smckusick usedarg++; 106551898Smckusick parsecred(cpoptarg, cr); 106651898Smckusick if (allflag == 0) { 106751898Smckusick *exflagsp |= MNT_EXPORTANON; 106851898Smckusick opt_flags |= OP_MAPALL; 106951898Smckusick } else 107051898Smckusick opt_flags |= OP_MAPROOT; 107151898Smckusick } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 107251898Smckusick *exflagsp |= MNT_EXKERB; 107351898Smckusick opt_flags |= OP_KERB; 107451898Smckusick } else if (cpoptarg && !strcmp(cpopt, "mask")) { 107551898Smckusick if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 107651898Smckusick syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 107751898Smckusick return (1); 107851898Smckusick } 107951898Smckusick usedarg++; 108051898Smckusick opt_flags |= OP_MASK; 108151898Smckusick } else if (cpoptarg && !strcmp(cpopt, "network")) { 108251898Smckusick if (grp->gr_type != GT_NULL) { 108351898Smckusick syslog(LOG_ERR, "Network/host conflict"); 108451898Smckusick return (1); 108551898Smckusick } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 108651898Smckusick syslog(LOG_ERR, "Bad net: %s", cpoptarg); 108751898Smckusick return (1); 108851898Smckusick } 108951898Smckusick grp->gr_type = GT_NET; 109051898Smckusick *has_hostp = 1; 109151898Smckusick usedarg++; 109251898Smckusick opt_flags |= OP_NET; 109351898Smckusick } else if (!strcmp(cpopt, "alldirs")) { 109451898Smckusick opt_flags |= OP_ALLDIRS; 109551898Smckusick #ifdef ISO 109651898Smckusick } else if (cpoptarg && !strcmp(cpopt, "iso")) { 109751898Smckusick if (get_isoaddr(cpoptarg, grp)) { 109851898Smckusick syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 109951898Smckusick return (1); 110051898Smckusick } 110151898Smckusick *has_hostp = 1; 110251898Smckusick usedarg++; 110351898Smckusick opt_flags |= OP_ISO; 110451898Smckusick #endif /* ISO */ 110551898Smckusick } else { 110651898Smckusick syslog(LOG_ERR, "Bad opt %s", cpopt); 110751898Smckusick return (1); 110851667Smckusick } 110951898Smckusick if (usedarg >= 0) { 111051898Smckusick *endcp = savedc2; 111151898Smckusick **endcpp = savedc; 111251898Smckusick if (usedarg > 0) { 111351898Smckusick *cpp = cp; 111451898Smckusick *endcpp = endcp; 111551898Smckusick } 111651898Smckusick return (0); 111751898Smckusick } 111851898Smckusick cpopt = cpoptend; 111951667Smckusick } 112051898Smckusick **endcpp = savedc; 112151898Smckusick return (0); 112251898Smckusick } 112351898Smckusick 112451898Smckusick /* 112551898Smckusick * Translate a character string to the corresponding list of network 112651898Smckusick * addresses for a hostname. 112751898Smckusick */ 112851898Smckusick get_host(cp, grp) 112951898Smckusick char *cp; 113051898Smckusick register struct grouplist *grp; 113151898Smckusick { 113251898Smckusick register struct hostent *hp, *nhp; 113351898Smckusick register char **addrp, **naddrp; 113451898Smckusick struct hostent t_host; 113551898Smckusick int i; 113651898Smckusick u_long saddr; 113751898Smckusick char *aptr[2]; 113851898Smckusick 113951898Smckusick if (grp->gr_type != GT_NULL) 114051898Smckusick return (1); 114151898Smckusick if ((hp = gethostbyname(cp)) == NULL) { 114251898Smckusick if (isdigit(*cp)) { 114351898Smckusick saddr = inet_addr(cp); 114451898Smckusick if (saddr == -1) { 114551898Smckusick syslog(LOG_ERR, "Inet_addr failed"); 114651898Smckusick return (1); 114751898Smckusick } 114851898Smckusick if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 114951898Smckusick AF_INET)) == NULL) { 115051898Smckusick hp = &t_host; 115151898Smckusick hp->h_name = cp; 115251898Smckusick hp->h_addrtype = AF_INET; 115351898Smckusick hp->h_length = sizeof (u_long); 115451898Smckusick hp->h_addr_list = aptr; 115551898Smckusick aptr[0] = (char *)&saddr; 115651898Smckusick aptr[1] = (char *)0; 115751898Smckusick } 115851898Smckusick } else { 115951898Smckusick syslog(LOG_ERR, "Gethostbyname failed"); 116051898Smckusick return (1); 116151898Smckusick } 116251898Smckusick } 116351898Smckusick grp->gr_type = GT_HOST; 116451898Smckusick nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 116551898Smckusick malloc(sizeof(struct hostent)); 116651898Smckusick if (nhp == (struct hostent *)0) 116751898Smckusick out_of_mem(); 116851898Smckusick bcopy((caddr_t)hp, (caddr_t)nhp, 116951898Smckusick sizeof(struct hostent)); 117051898Smckusick i = strlen(hp->h_name)+1; 117151898Smckusick nhp->h_name = (char *)malloc(i); 117251898Smckusick if (nhp->h_name == (char *)0) 117351898Smckusick out_of_mem(); 117451898Smckusick bcopy(hp->h_name, nhp->h_name, i); 117551898Smckusick addrp = hp->h_addr_list; 117651898Smckusick i = 1; 117751898Smckusick while (*addrp++) 117851898Smckusick i++; 117951898Smckusick naddrp = nhp->h_addr_list = (char **) 118051898Smckusick malloc(i*sizeof(char *)); 118151898Smckusick if (naddrp == (char **)0) 118251898Smckusick out_of_mem(); 118351898Smckusick addrp = hp->h_addr_list; 118451898Smckusick while (*addrp) { 118551898Smckusick *naddrp = (char *) 118651898Smckusick malloc(hp->h_length); 118751898Smckusick if (*naddrp == (char *)0) 118851898Smckusick out_of_mem(); 118951898Smckusick bcopy(*addrp, *naddrp, 119051898Smckusick hp->h_length); 119151898Smckusick addrp++; 119251898Smckusick naddrp++; 119351898Smckusick } 119451898Smckusick *naddrp = (char *)0; 119551898Smckusick return (0); 119651898Smckusick } 119751898Smckusick 119851898Smckusick /* 119951898Smckusick * Free up an exports list component 120051898Smckusick */ 120151898Smckusick void 120251898Smckusick free_exp(ep) 120351898Smckusick register struct exportlist *ep; 120451898Smckusick { 120551898Smckusick 120651898Smckusick if (ep->ex_defdir) { 120751898Smckusick free_host(ep->ex_defdir->dp_hosts); 120851898Smckusick free((caddr_t)ep->ex_defdir); 120951898Smckusick } 121051898Smckusick if (ep->ex_fsdir) 121151898Smckusick free(ep->ex_fsdir); 121251898Smckusick free_dir(ep->ex_dirl); 121351898Smckusick free((caddr_t)ep); 121451898Smckusick } 121551898Smckusick 121651898Smckusick /* 121751898Smckusick * Free hosts. 121851898Smckusick */ 121951898Smckusick void 122051898Smckusick free_host(hp) 122151898Smckusick register struct hostlist *hp; 122251898Smckusick { 122351898Smckusick register struct hostlist *hp2; 122451898Smckusick 122551898Smckusick while (hp) { 122651898Smckusick hp2 = hp; 122751898Smckusick hp = hp->ht_next; 122851898Smckusick free((caddr_t)hp2); 122951898Smckusick } 123051898Smckusick } 123151898Smckusick 123251898Smckusick struct hostlist * 123351898Smckusick get_ht() 123451898Smckusick { 123551898Smckusick register struct hostlist *hp; 123651898Smckusick 123751898Smckusick hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 123851898Smckusick if (hp == (struct hostlist *)0) 123951898Smckusick out_of_mem(); 124051898Smckusick hp->ht_next = (struct hostlist *)0; 124151898Smckusick return (hp); 124251898Smckusick } 124351898Smckusick 124451898Smckusick #ifdef ISO 124551898Smckusick /* 124651898Smckusick * Translate an iso address. 124751898Smckusick */ 124851898Smckusick get_isoaddr(cp, grp) 124951898Smckusick char *cp; 125051898Smckusick struct grouplist *grp; 125151898Smckusick { 125251898Smckusick struct iso_addr *isop; 125351898Smckusick struct sockaddr_iso *isoaddr; 125451898Smckusick 125551898Smckusick if (grp->gr_type != GT_NULL) 125651898Smckusick return (1); 125751898Smckusick if ((isop = iso_addr(cp)) == NULL) { 125851898Smckusick syslog(LOG_ERR, 125951898Smckusick "iso_addr failed, ignored"); 126051898Smckusick return (1); 126151898Smckusick } 126251898Smckusick isoaddr = (struct sockaddr_iso *) 126351898Smckusick malloc(sizeof (struct sockaddr_iso)); 126451898Smckusick if (isoaddr == (struct sockaddr_iso *)0) 126551898Smckusick out_of_mem(); 126651898Smckusick bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 126751898Smckusick bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 126851898Smckusick sizeof (struct iso_addr)); 126951898Smckusick isoaddr->siso_len = sizeof (struct sockaddr_iso); 127051898Smckusick isoaddr->siso_family = AF_ISO; 127151898Smckusick grp->gr_type = GT_ISO; 127251898Smckusick grp->gr_ptr.gt_isoaddr = isoaddr; 127351898Smckusick return (0); 127451898Smckusick } 127551898Smckusick #endif /* ISO */ 127651898Smckusick 127751898Smckusick /* 127851898Smckusick * Out of memory, fatal 127951898Smckusick */ 128051898Smckusick void 128151898Smckusick out_of_mem() 128251898Smckusick { 128351898Smckusick 128451898Smckusick syslog(LOG_ERR, "Out of memory"); 128551667Smckusick exit(2); 128651667Smckusick } 128751667Smckusick 128851898Smckusick /* 128951898Smckusick * Do the mount syscall with the update flag to push the export info into 129051898Smckusick * the kernel. 129151898Smckusick */ 129251898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 129351667Smckusick struct exportlist *ep; 129451667Smckusick struct grouplist *grp; 129551898Smckusick int exflags; 129651667Smckusick struct ucred *anoncrp; 129751898Smckusick char *dirp; 129851898Smckusick int dirplen; 129951898Smckusick struct statfs *fsb; 130051667Smckusick { 130151898Smckusick register char *cp = (char *)0; 130251667Smckusick register u_long **addrp; 130351898Smckusick int done; 130451898Smckusick char savedc; 130551898Smckusick struct sockaddr_in sin, imask; 1306*52109Smckusick struct ufs_args args; 130751898Smckusick u_long net; 130851667Smckusick 130951667Smckusick args.fspec = 0; 131051667Smckusick args.exflags = exflags; 131151667Smckusick args.anon = *anoncrp; 131251667Smckusick sin.sin_family = AF_INET; 131351667Smckusick sin.sin_port = 0; 131451667Smckusick sin.sin_len = sizeof(sin); 131551898Smckusick imask.sin_family = AF_INET; 131651898Smckusick imask.sin_port = 0; 131751898Smckusick imask.sin_len = sizeof(sin); 131851898Smckusick if (grp->gr_type == GT_HOST) 131951667Smckusick addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 132051898Smckusick else 132151898Smckusick addrp = (u_long **)0; 132251667Smckusick done = FALSE; 132351898Smckusick while (!done) { 132451898Smckusick switch (grp->gr_type) { 132551898Smckusick case GT_HOST: 132651898Smckusick if (addrp) 132751712Smckusick sin.sin_addr.s_addr = **addrp; 132851712Smckusick else 132951667Smckusick sin.sin_addr.s_addr = INADDR_ANY; 133051667Smckusick args.saddr = (struct sockaddr *)&sin; 133151667Smckusick args.slen = sizeof(sin); 133251898Smckusick args.msklen = 0; 133351898Smckusick break; 133451898Smckusick case GT_NET: 133551898Smckusick if (grp->gr_ptr.gt_net.nt_mask) 133651898Smckusick imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 133751898Smckusick else { 133851898Smckusick net = ntohl(grp->gr_ptr.gt_net.nt_net); 133951898Smckusick if (IN_CLASSA(net)) 134051898Smckusick imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 134151898Smckusick else if (IN_CLASSB(net)) 134251898Smckusick imask.sin_addr.s_addr = 134351898Smckusick inet_addr("255.255.0.0"); 134451898Smckusick else 134551898Smckusick imask.sin_addr.s_addr = 134651898Smckusick inet_addr("255.255.255.0"); 134751898Smckusick grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 134851898Smckusick } 134951898Smckusick sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 135051898Smckusick args.saddr = (struct sockaddr *)&sin; 135151898Smckusick args.slen = sizeof (sin); 135251898Smckusick args.smask = (struct sockaddr *)&imask; 135351898Smckusick args.msklen = sizeof (imask); 135451898Smckusick break; 135551667Smckusick #ifdef ISO 135651898Smckusick case GT_ISO: 135751667Smckusick args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 135851667Smckusick args.slen = sizeof (struct sockaddr_iso); 135951898Smckusick args.msklen = 0; 136051898Smckusick break; 136151667Smckusick #endif /* ISO */ 136251898Smckusick default: 136351667Smckusick syslog(LOG_ERR, "Bad grouptype"); 136451898Smckusick if (cp) 136551898Smckusick *cp = savedc; 136651898Smckusick return (1); 136751898Smckusick }; 1368*52109Smckusick 1369*52109Smckusick /* 1370*52109Smckusick * XXX: 1371*52109Smckusick * Maybe I should just use the fsb->f_mntonname path instead 1372*52109Smckusick * of looping back up the dirp to the mount point?? 1373*52109Smckusick * Also, needs to know how to export all types of local 1374*52109Smckusick * exportable file systems and not just MOUNT_UFS. 1375*52109Smckusick */ 1376*52109Smckusick while (mount(fsb->f_type, dirp, 1377*52109Smckusick fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 137851898Smckusick if (cp) 137951898Smckusick *cp-- = savedc; 138051898Smckusick else 138151898Smckusick cp = dirp + dirplen - 1; 138251667Smckusick if (errno == EPERM) { 138351667Smckusick syslog(LOG_ERR, 138451898Smckusick "Can't change attributes for %s.\n", dirp); 138551898Smckusick return (1); 138651667Smckusick } 138751898Smckusick if (opt_flags & OP_ALLDIRS) { 138851898Smckusick syslog(LOG_ERR, "Not root dir"); 138951898Smckusick return (1); 139051898Smckusick } 139151667Smckusick /* back up over the last component */ 139251898Smckusick while (*cp == '/' && cp > dirp) 139351667Smckusick cp--; 139451898Smckusick while (*(cp - 1) != '/' && cp > dirp) 139551667Smckusick cp--; 139651898Smckusick if (cp == dirp) { 139751898Smckusick if (debug) 139851667Smckusick fprintf(stderr,"mnt unsucc\n"); 139951898Smckusick syslog(LOG_ERR, "Can't export %s", dirp); 140051898Smckusick return (1); 140151667Smckusick } 140251667Smckusick savedc = *cp; 140351667Smckusick *cp = '\0'; 140451667Smckusick } 140551898Smckusick if (addrp) { 140651667Smckusick ++addrp; 140751898Smckusick if (*addrp == (u_long *)0) 140851667Smckusick done = TRUE; 140951898Smckusick } else 141051898Smckusick done = TRUE; 141151898Smckusick } 141251898Smckusick if (cp) 141351898Smckusick *cp = savedc; 141451898Smckusick return (0); 141551898Smckusick } 141651898Smckusick 141751898Smckusick /* 141851898Smckusick * Translate a net address. 141951898Smckusick */ 142051898Smckusick get_net(cp, net, maskflg) 142151898Smckusick char *cp; 142251898Smckusick struct netmsk *net; 142351898Smckusick int maskflg; 142451898Smckusick { 142551898Smckusick register struct netent *np; 142651898Smckusick register long netaddr; 142751898Smckusick struct in_addr inetaddr, inetaddr2; 142851898Smckusick char *name; 142951898Smckusick 143051898Smckusick if (np = getnetbyname(cp)) 143151898Smckusick inetaddr = inet_makeaddr(np->n_net, 0); 143251898Smckusick else if (isdigit(*cp)) { 143351898Smckusick if ((netaddr = inet_network(cp)) == -1) 143451898Smckusick return (1); 143551898Smckusick inetaddr = inet_makeaddr(netaddr, 0); 143651898Smckusick /* 143751898Smckusick * Due to arbritrary subnet masks, you don't know how many 143851898Smckusick * bits to shift the address to make it into a network, 143951898Smckusick * however you do know how to make a network address into 144051898Smckusick * a host with host == 0 and then compare them. 144151898Smckusick * (What a pest) 144251898Smckusick */ 144351898Smckusick if (!maskflg) { 144451898Smckusick setnetent(0); 144551898Smckusick while (np = getnetent()) { 144651898Smckusick inetaddr2 = inet_makeaddr(np->n_net, 0); 144751898Smckusick if (inetaddr2.s_addr == inetaddr.s_addr) 144851898Smckusick break; 144951898Smckusick } 145051898Smckusick endnetent(); 145151667Smckusick } 145251898Smckusick } else 145351898Smckusick return (1); 145451898Smckusick if (maskflg) 145551898Smckusick net->nt_mask = inetaddr.s_addr; 145651898Smckusick else { 145751898Smckusick if (np) 145851898Smckusick name = np->n_name; 145951898Smckusick else 146051898Smckusick name = inet_ntoa(inetaddr); 146151898Smckusick net->nt_name = (char *)malloc(strlen(name) + 1); 146251898Smckusick if (net->nt_name == (char *)0) 146351898Smckusick out_of_mem(); 146451898Smckusick strcpy(net->nt_name, name); 146551898Smckusick net->nt_net = inetaddr.s_addr; 146638460Smckusick } 146751898Smckusick return (0); 146838460Smckusick } 146938460Smckusick 147038460Smckusick /* 147138460Smckusick * Parse out the next white space separated field 147238460Smckusick */ 147351667Smckusick void 147438460Smckusick nextfield(cp, endcp) 147538460Smckusick char **cp; 147638460Smckusick char **endcp; 147738460Smckusick { 147838460Smckusick register char *p; 147938460Smckusick 148038460Smckusick p = *cp; 148138460Smckusick while (*p == ' ' || *p == '\t') 148238460Smckusick p++; 148351898Smckusick if (*p == '\n' || *p == '\0') 148438460Smckusick *cp = *endcp = p; 148551898Smckusick else { 148651898Smckusick *cp = p++; 148751898Smckusick while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 148851898Smckusick p++; 148951898Smckusick *endcp = p; 149038460Smckusick } 149138460Smckusick } 149239681Smckusick 149339681Smckusick /* 149451898Smckusick * Get an exports file line. Skip over blank lines and handle line 149551898Smckusick * continuations. 149639681Smckusick */ 149751898Smckusick get_line() 149839681Smckusick { 149951898Smckusick register char *p, *cp; 150051898Smckusick register int len; 150151898Smckusick int totlen, cont_line; 150239681Smckusick 150351898Smckusick /* 150451898Smckusick * Loop around ignoring blank lines and getting all continuation lines. 150551898Smckusick */ 150651898Smckusick p = line; 150751898Smckusick totlen = 0; 150851898Smckusick do { 150951898Smckusick if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 151051898Smckusick return (0); 151151898Smckusick len = strlen(p); 151251898Smckusick cp = p + len - 1; 151351898Smckusick cont_line = 0; 151451898Smckusick while (cp >= p && 151551898Smckusick (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 151651898Smckusick if (*cp == '\\') 151751898Smckusick cont_line = 1; 151851898Smckusick cp--; 151951898Smckusick len--; 152051898Smckusick } 152151898Smckusick *++cp = '\0'; 152251898Smckusick if (len > 0) { 152351898Smckusick totlen += len; 152451898Smckusick if (totlen >= LINESIZ) { 152551898Smckusick syslog(LOG_ERR, "Exports line too long"); 152651898Smckusick exit(2); 152751898Smckusick } 152851898Smckusick p = cp; 152951898Smckusick } 153051898Smckusick } while (totlen == 0 || cont_line); 153151898Smckusick return (1); 153244015Smckusick } 153344015Smckusick 153451667Smckusick /* 153551667Smckusick * Parse a description of a credential. 153651667Smckusick */ 153751667Smckusick parsecred(namelist, cr) 153851667Smckusick char *namelist; 153951667Smckusick register struct ucred *cr; 154051667Smckusick { 154151667Smckusick register char *name; 154251667Smckusick register int cnt; 154351667Smckusick char *names; 154451667Smckusick struct passwd *pw; 154551667Smckusick struct group *gr; 154651667Smckusick int ngroups, groups[NGROUPS + 1]; 154751667Smckusick 154851667Smckusick /* 154951667Smckusick * Set up the unpriviledged user. 155051667Smckusick */ 155151667Smckusick cr->cr_ref = 1; 155251667Smckusick cr->cr_uid = -2; 155351667Smckusick cr->cr_groups[0] = -2; 155451667Smckusick cr->cr_ngroups = 1; 155551667Smckusick /* 155651667Smckusick * Get the user's password table entry. 155751667Smckusick */ 155851667Smckusick names = strsep(&namelist, " \t\n"); 155951667Smckusick name = strsep(&names, ":"); 156051667Smckusick if (isdigit(*name) || *name == '-') 156151667Smckusick pw = getpwuid(atoi(name)); 156251667Smckusick else 156351667Smckusick pw = getpwnam(name); 156451667Smckusick /* 156551667Smckusick * Credentials specified as those of a user. 156651667Smckusick */ 156751667Smckusick if (names == NULL) { 156851667Smckusick if (pw == NULL) { 156951667Smckusick syslog(LOG_ERR, "Unknown user: %s\n", name); 157051667Smckusick return; 157151667Smckusick } 157251667Smckusick cr->cr_uid = pw->pw_uid; 157351667Smckusick ngroups = NGROUPS + 1; 157451667Smckusick if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 157551667Smckusick syslog(LOG_ERR, "Too many groups\n"); 157651667Smckusick /* 157751667Smckusick * Convert from int's to gid_t's and compress out duplicate 157851667Smckusick */ 157951667Smckusick cr->cr_ngroups = ngroups - 1; 158051667Smckusick cr->cr_groups[0] = groups[0]; 158151667Smckusick for (cnt = 2; cnt < ngroups; cnt++) 158251667Smckusick cr->cr_groups[cnt - 1] = groups[cnt]; 158351667Smckusick return; 158451667Smckusick } 158551667Smckusick /* 158651667Smckusick * Explicit credential specified as a colon separated list: 158751667Smckusick * uid:gid:gid:... 158851667Smckusick */ 158951667Smckusick if (pw != NULL) 159051667Smckusick cr->cr_uid = pw->pw_uid; 159151667Smckusick else if (isdigit(*name) || *name == '-') 159251667Smckusick cr->cr_uid = atoi(name); 159351667Smckusick else { 159451667Smckusick syslog(LOG_ERR, "Unknown user: %s\n", name); 159551667Smckusick return; 159651667Smckusick } 159751667Smckusick cr->cr_ngroups = 0; 159851667Smckusick while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 159951667Smckusick name = strsep(&names, ":"); 160051667Smckusick if (isdigit(*name) || *name == '-') { 160151667Smckusick cr->cr_groups[cr->cr_ngroups++] = atoi(name); 160251667Smckusick } else { 160351667Smckusick if ((gr = getgrnam(name)) == NULL) { 160451667Smckusick syslog(LOG_ERR, "Unknown group: %s\n", name); 160551667Smckusick continue; 160651667Smckusick } 160751667Smckusick cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 160851667Smckusick } 160951667Smckusick } 161051667Smckusick if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 161151667Smckusick syslog(LOG_ERR, "Too many groups\n"); 161251667Smckusick } 161351667Smckusick 161444015Smckusick #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 161544015Smckusick /* 161644015Smckusick * Routines that maintain the remote mounttab 161744015Smckusick */ 161851667Smckusick void 161951667Smckusick get_mountlist() 162044015Smckusick { 162144015Smckusick register struct mountlist *mlp, **mlpp; 162244015Smckusick register char *eos, *dirp; 162344015Smckusick int len; 162444015Smckusick char str[STRSIZ]; 162544015Smckusick FILE *mlfile; 162644015Smckusick 162751712Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 162851667Smckusick syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 162944015Smckusick return; 163044015Smckusick } 163144015Smckusick mlpp = &mlhead; 163244015Smckusick while (fgets(str, STRSIZ, mlfile) != NULL) { 163344015Smckusick if ((dirp = index(str, '\t')) == NULL && 163444015Smckusick (dirp = index(str, ' ')) == NULL) 163544015Smckusick continue; 163644015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 163744015Smckusick len = dirp-str; 163844015Smckusick if (len > RPCMNT_NAMELEN) 163944015Smckusick len = RPCMNT_NAMELEN; 164044015Smckusick bcopy(str, mlp->ml_host, len); 164144015Smckusick mlp->ml_host[len] = '\0'; 164244015Smckusick while (*dirp == '\t' || *dirp == ' ') 164344015Smckusick dirp++; 164444015Smckusick if ((eos = index(dirp, '\t')) == NULL && 164544015Smckusick (eos = index(dirp, ' ')) == NULL && 164644015Smckusick (eos = index(dirp, '\n')) == NULL) 164744015Smckusick len = strlen(dirp); 164844015Smckusick else 164944015Smckusick len = eos-dirp; 165044015Smckusick if (len > RPCMNT_PATHLEN) 165144015Smckusick len = RPCMNT_PATHLEN; 165244015Smckusick bcopy(dirp, mlp->ml_dirp, len); 165344015Smckusick mlp->ml_dirp[len] = '\0'; 165444015Smckusick mlp->ml_next = (struct mountlist *)0; 165544015Smckusick *mlpp = mlp; 165644015Smckusick mlpp = &mlp->ml_next; 165744015Smckusick } 165844015Smckusick fclose(mlfile); 165944015Smckusick } 166044015Smckusick 166151667Smckusick void 166251667Smckusick del_mlist(hostp, dirp) 166344015Smckusick register char *hostp, *dirp; 166444015Smckusick { 166544015Smckusick register struct mountlist *mlp, **mlpp; 166651712Smckusick struct mountlist *mlp2; 166744015Smckusick FILE *mlfile; 166844015Smckusick int fnd = 0; 166944015Smckusick 167044015Smckusick mlpp = &mlhead; 167144015Smckusick mlp = mlhead; 167244015Smckusick while (mlp) { 167344015Smckusick if (!strcmp(mlp->ml_host, hostp) && 167444015Smckusick (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 167544015Smckusick fnd = 1; 167651712Smckusick mlp2 = mlp; 167751712Smckusick *mlpp = mlp = mlp->ml_next; 167851712Smckusick free((caddr_t)mlp2); 167951712Smckusick } else { 168051712Smckusick mlpp = &mlp->ml_next; 168151712Smckusick mlp = mlp->ml_next; 168239681Smckusick } 168339681Smckusick } 168444015Smckusick if (fnd) { 168544015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 168651898Smckusick syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 168744015Smckusick return; 168844015Smckusick } 168944015Smckusick mlp = mlhead; 169044015Smckusick while (mlp) { 169144015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 169244015Smckusick mlp = mlp->ml_next; 169344015Smckusick } 169444015Smckusick fclose(mlfile); 169544015Smckusick } 169639681Smckusick } 169744015Smckusick 169851667Smckusick void 169951667Smckusick add_mlist(hostp, dirp) 170044015Smckusick register char *hostp, *dirp; 170144015Smckusick { 170244015Smckusick register struct mountlist *mlp, **mlpp; 170344015Smckusick FILE *mlfile; 170444015Smckusick 170544015Smckusick mlpp = &mlhead; 170644015Smckusick mlp = mlhead; 170744015Smckusick while (mlp) { 170844015Smckusick if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 170944015Smckusick return; 171044015Smckusick mlpp = &mlp->ml_next; 171144015Smckusick mlp = mlp->ml_next; 171244015Smckusick } 171344015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 171444015Smckusick strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 171544015Smckusick mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 171644015Smckusick strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 171744015Smckusick mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 171844015Smckusick mlp->ml_next = (struct mountlist *)0; 171944015Smckusick *mlpp = mlp; 172044015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 172151898Smckusick syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 172244015Smckusick return; 172344015Smckusick } 172444015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 172544015Smckusick fclose(mlfile); 172644015Smckusick } 172744015Smckusick 172844015Smckusick /* 172944015Smckusick * This function is called via. SIGTERM when the system is going down. 173044015Smckusick * It sends a broadcast RPCMNT_UMNTALL. 173144015Smckusick */ 173246709Sbostic void 173344015Smckusick send_umntall() 173444015Smckusick { 173544015Smckusick (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 173644015Smckusick xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 173751667Smckusick exit(0); 173844015Smckusick } 173944015Smckusick 174044015Smckusick umntall_each(resultsp, raddr) 174144015Smckusick caddr_t resultsp; 174244015Smckusick struct sockaddr_in *raddr; 174344015Smckusick { 174444015Smckusick return (1); 174544015Smckusick } 174644015Smckusick 174744015Smckusick /* 174851667Smckusick * Free up a group list. 174951667Smckusick */ 175051667Smckusick void 175151667Smckusick free_grp(grp) 175251667Smckusick register struct grouplist *grp; 175351667Smckusick { 175451667Smckusick register char **addrp; 175551667Smckusick 175651898Smckusick if (grp->gr_type == GT_HOST) { 175751712Smckusick if (grp->gr_ptr.gt_hostent->h_name) { 175851712Smckusick addrp = grp->gr_ptr.gt_hostent->h_addr_list; 175951712Smckusick while (addrp && *addrp) 176051712Smckusick free(*addrp++); 176151712Smckusick free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 176251712Smckusick free(grp->gr_ptr.gt_hostent->h_name); 176351712Smckusick } 176451667Smckusick free((caddr_t)grp->gr_ptr.gt_hostent); 176551898Smckusick } else if (grp->gr_type == GT_NET) { 176651898Smckusick if (grp->gr_ptr.gt_net.nt_name) 176751898Smckusick free(grp->gr_ptr.gt_net.nt_name); 176851667Smckusick } 176951667Smckusick #ifdef ISO 177051898Smckusick else if (grp->gr_type == GT_ISO) 177151667Smckusick free((caddr_t)grp->gr_ptr.gt_isoaddr); 177251667Smckusick #endif 177351667Smckusick free((caddr_t)grp); 177451667Smckusick } 177551667Smckusick 177651667Smckusick /* 177751667Smckusick * char *realpath(const char *path, char resolved_path[MAXPATHLEN]) 177851667Smckusick * 177951667Smckusick * find the real name of path, by removing all ".", ".." 178051667Smckusick * and symlink components. 178151667Smckusick * 178251667Smckusick * Jan-Simon Pendry, September 1991. 178351667Smckusick */ 178451667Smckusick char * 178551667Smckusick realpath(path, resolved) 178651667Smckusick char *path; 178751667Smckusick char resolved[MAXPATHLEN]; 178851667Smckusick { 178951667Smckusick int d = open(".", O_RDONLY); 179051667Smckusick int rootd = 0; 179151667Smckusick char *p, *q; 179251667Smckusick struct stat stb; 179351667Smckusick char wbuf[MAXPATHLEN]; 179451667Smckusick 179551667Smckusick strcpy(resolved, path); 179651667Smckusick 179751667Smckusick if (d < 0) 179851667Smckusick return 0; 179951667Smckusick 180051667Smckusick loop:; 180151667Smckusick q = strrchr(resolved, '/'); 180251667Smckusick if (q) { 180351667Smckusick p = q + 1; 180451667Smckusick if (q == resolved) 180551667Smckusick q = "/"; 180651667Smckusick else { 180751667Smckusick do 180851667Smckusick --q; 180951667Smckusick while (q > resolved && *q == '/'); 181051667Smckusick q[1] = '\0'; 181151667Smckusick q = resolved; 181251667Smckusick } 181351667Smckusick if (chdir(q) < 0) 181451667Smckusick goto out; 181551667Smckusick } else 181651667Smckusick p = resolved; 181751667Smckusick 181851667Smckusick if (lstat(p, &stb) == 0) { 181951667Smckusick if (S_ISLNK(stb.st_mode)) { 182051667Smckusick int n = readlink(p, resolved, MAXPATHLEN); 182151667Smckusick if (n < 0) 182251667Smckusick goto out; 182351667Smckusick resolved[n] = '\0'; 182451667Smckusick goto loop; 182551667Smckusick } 182651667Smckusick if (S_ISDIR(stb.st_mode)) { 182751667Smckusick if (chdir(p) < 0) 182851667Smckusick goto out; 182951667Smckusick p = ""; 183051667Smckusick } 183151667Smckusick } 183251667Smckusick 183351667Smckusick strcpy(wbuf, p); 183451667Smckusick if (getcwd(resolved, MAXPATHLEN) == 0) 183551667Smckusick goto out; 183651667Smckusick if (resolved[0] == '/' && resolved[1] == '\0') 183751667Smckusick rootd = 1; 183851667Smckusick 183951667Smckusick if (*wbuf) { 184051667Smckusick if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) { 184151667Smckusick errno = ENAMETOOLONG; 184251667Smckusick goto out; 184351667Smckusick } 184451667Smckusick if (rootd == 0) 184551667Smckusick strcat(resolved, "/"); 184651667Smckusick strcat(resolved, wbuf); 184751667Smckusick } 184851667Smckusick 184951667Smckusick if (fchdir(d) < 0) 185051667Smckusick goto out; 185151667Smckusick (void) close(d); 185251667Smckusick 185351667Smckusick return resolved; 185451667Smckusick 185551667Smckusick out:; 185651667Smckusick (void) close(d); 185751667Smckusick return 0; 185851667Smckusick } 185951711Smckusick 186051711Smckusick #ifdef DEBUG 186151711Smckusick void 186251711Smckusick SYSLOG(int pri, const char *fmt, ...) 186351711Smckusick { 186451711Smckusick va_list ap; 186551711Smckusick 186651711Smckusick va_start(ap, fmt); 186751711Smckusick vfprintf(stderr, fmt, ap); 186851711Smckusick va_end(ap); 186951711Smckusick } 187051711Smckusick #endif /* DEBUG */ 187151898Smckusick 187251898Smckusick /* 187351898Smckusick * Check options for consistency. 187451898Smckusick */ 187551898Smckusick check_options(dp) 187651898Smckusick struct dirlist *dp; 187751898Smckusick { 187851898Smckusick 187951898Smckusick if (dp == (struct dirlist *)0) 188051898Smckusick return (1); 188151898Smckusick if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 188251898Smckusick (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 188351898Smckusick (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 188451898Smckusick syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 188551898Smckusick return (1); 188651898Smckusick } 188751898Smckusick if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 188851898Smckusick syslog(LOG_ERR, "-mask requires -net"); 188951898Smckusick return (1); 189051898Smckusick } 189151898Smckusick if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 189251898Smckusick syslog(LOG_ERR, "-net and -iso mutually exclusive"); 189351898Smckusick return (1); 189451898Smckusick } 189551898Smckusick if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 189651898Smckusick syslog(LOG_ERR, "-alldir has multiple directories"); 189751898Smckusick return (1); 189851898Smckusick } 189951898Smckusick return (0); 190051898Smckusick } 1901