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*68095Shibler static char sccsid[] = "@(#)mountd.c 8.11 (Berkeley) 12/27/94"; 1938460Smckusick #endif not lint 2038460Smckusick 2138460Smckusick #include <sys/param.h> 2265863Sbostic #include <sys/file.h> 2338460Smckusick #include <sys/ioctl.h> 2438460Smckusick #include <sys/mount.h> 2538460Smckusick #include <sys/socket.h> 2665863Sbostic #include <sys/stat.h> 2752109Smckusick #include <sys/syslog.h> 2865863Sbostic #include <sys/ucred.h> 2965863Sbostic 3038460Smckusick #include <rpc/rpc.h> 3138460Smckusick #include <rpc/pmap_clnt.h> 3238460Smckusick #include <rpc/pmap_prot.h> 3351667Smckusick #ifdef ISO 3451667Smckusick #include <netiso/iso.h> 3551667Smckusick #endif 3638460Smckusick #include <nfs/rpcv2.h> 3738460Smckusick #include <nfs/nfsv2.h> 3865863Sbostic 3966163Spendry #include <arpa/inet.h> 4066163Spendry 4166163Spendry #include <ctype.h> 4265863Sbostic #include <errno.h> 4365863Sbostic #include <grp.h> 4465863Sbostic #include <netdb.h> 4565863Sbostic #include <pwd.h> 4665863Sbostic #include <signal.h> 4765863Sbostic #include <stdio.h> 4865863Sbostic #include <stdlib.h> 4965863Sbostic #include <string.h> 5065863Sbostic #include <unistd.h> 5165863Sbostic #include "pathnames.h" 5238460Smckusick 5366163Spendry #ifdef DEBUG 5466163Spendry #include <stdarg.h> 5566163Spendry #endif 5666163Spendry 5738460Smckusick /* 5838460Smckusick * Structures for keeping the mount list and export list 5938460Smckusick */ 6038460Smckusick struct mountlist { 6144015Smckusick struct mountlist *ml_next; 6238460Smckusick char ml_host[RPCMNT_NAMELEN+1]; 6338460Smckusick char ml_dirp[RPCMNT_PATHLEN+1]; 6438460Smckusick }; 6538460Smckusick 6651898Smckusick struct dirlist { 6751898Smckusick struct dirlist *dp_left; 6851898Smckusick struct dirlist *dp_right; 6951898Smckusick int dp_flag; 7051898Smckusick struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 7151898Smckusick char dp_dirp[1]; /* Actually malloc'd to size of dir */ 7251898Smckusick }; 7351898Smckusick /* dp_flag bits */ 7451898Smckusick #define DP_DEFSET 0x1 7551898Smckusick 7638460Smckusick struct exportlist { 7738460Smckusick struct exportlist *ex_next; 7851898Smckusick struct dirlist *ex_dirl; 7951898Smckusick struct dirlist *ex_defdir; 8051898Smckusick int ex_flag; 8151898Smckusick fsid_t ex_fs; 8251898Smckusick char *ex_fsdir; 8338460Smckusick }; 8451898Smckusick /* ex_flag bits */ 8552109Smckusick #define EX_LINKED 0x1 8638460Smckusick 8751898Smckusick struct netmsk { 8851898Smckusick u_long nt_net; 8951898Smckusick u_long nt_mask; 9051898Smckusick char *nt_name; 9151898Smckusick }; 9251898Smckusick 9351667Smckusick union grouptypes { 9451667Smckusick struct hostent *gt_hostent; 9551898Smckusick struct netmsk gt_net; 9651667Smckusick #ifdef ISO 9751667Smckusick struct sockaddr_iso *gt_isoaddr; 9851667Smckusick #endif 9951667Smckusick }; 10051667Smckusick 10138460Smckusick struct grouplist { 10251898Smckusick int gr_type; 10351667Smckusick union grouptypes gr_ptr; 10438460Smckusick struct grouplist *gr_next; 10538460Smckusick }; 10651898Smckusick /* Group types */ 10751898Smckusick #define GT_NULL 0x0 10851898Smckusick #define GT_HOST 0x1 10951898Smckusick #define GT_NET 0x2 11051898Smckusick #define GT_ISO 0x4 11138460Smckusick 11251898Smckusick struct hostlist { 11351898Smckusick struct grouplist *ht_grp; 11451898Smckusick struct hostlist *ht_next; 11551667Smckusick }; 11651667Smckusick 11738460Smckusick /* Global defs */ 11866163Spendry char *add_expdir __P((struct dirlist **, char *, int)); 11966163Spendry void add_dlist __P((struct dirlist **, struct dirlist *, 12066163Spendry struct grouplist *)); 12166163Spendry void add_mlist __P((char *, char *)); 12266163Spendry int check_dirpath __P((char *)); 12366163Spendry int check_options __P((struct dirlist *)); 12466163Spendry int chk_host __P((struct dirlist *, u_long, int *)); 12566163Spendry void del_mlist __P((char *, char *)); 12666163Spendry struct dirlist *dirp_search __P((struct dirlist *, char *)); 12766163Spendry int do_mount __P((struct exportlist *, struct grouplist *, int, 12866163Spendry struct ucred *, char *, int, struct statfs *)); 12966163Spendry int do_opt __P((char **, char **, struct exportlist *, struct grouplist *, 13066163Spendry int *, int *, struct ucred *)); 13166163Spendry struct exportlist *ex_search __P((fsid_t *)); 13266163Spendry struct exportlist *get_exp __P((void)); 13366163Spendry void free_dir __P((struct dirlist *)); 13466163Spendry void free_exp __P((struct exportlist *)); 13566163Spendry void free_grp __P((struct grouplist *)); 13666163Spendry void free_host __P((struct hostlist *)); 13766163Spendry void get_exportlist __P((void)); 13866163Spendry int get_host __P((char *, struct grouplist *)); 13966163Spendry struct hostlist *get_ht __P((void)); 14066163Spendry int get_line __P((void)); 14166163Spendry void get_mountlist __P((void)); 14266163Spendry int get_net __P((char *, struct netmsk *, int)); 14366163Spendry void getexp_err __P((struct exportlist *, struct grouplist *)); 14466163Spendry struct grouplist *get_grp __P((void)); 14566163Spendry void hang_dirp __P((struct dirlist *, struct grouplist *, 14666163Spendry struct exportlist *, int)); 14766163Spendry void mntsrv __P((struct svc_req *, SVCXPRT *)); 14866163Spendry void nextfield __P((char **, char **)); 14966163Spendry void out_of_mem __P((void)); 15066163Spendry void parsecred __P((char *, struct ucred *)); 15166163Spendry int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *)); 15266163Spendry int scan_tree __P((struct dirlist *, u_long)); 15366163Spendry void send_umntall __P((void)); 15466163Spendry int umntall_each __P((caddr_t, struct sockaddr_in *)); 15566163Spendry int xdr_dir __P((XDR *, char *)); 15666163Spendry int xdr_explist __P((XDR *, caddr_t)); 15766163Spendry int xdr_fhs __P((XDR *, nfsv2fh_t *)); 15866163Spendry int xdr_mlist __P((XDR *, caddr_t)); 15966163Spendry 16066163Spendry /* C library */ 16166163Spendry int getnetgrent(); 16266163Spendry void endnetgrent(); 16366163Spendry void setnetgrent(); 16466163Spendry 16551667Smckusick #ifdef ISO 16651667Smckusick struct iso_addr *iso_addr(); 16751667Smckusick #endif 16866163Spendry 16951898Smckusick struct exportlist *exphead; 17044015Smckusick struct mountlist *mlhead; 17151898Smckusick struct grouplist *grphead; 17238460Smckusick char exname[MAXPATHLEN]; 17351667Smckusick struct ucred def_anon = { 17466163Spendry 1, 17551667Smckusick (uid_t) -2, 17651667Smckusick 1, 17766163Spendry { (gid_t) -2 } 17851667Smckusick }; 17967701Smckusick int resvport_only = 1; 18051898Smckusick int opt_flags; 18151898Smckusick /* Bits for above */ 18251898Smckusick #define OP_MAPROOT 0x01 18351898Smckusick #define OP_MAPALL 0x02 18451898Smckusick #define OP_KERB 0x04 18551898Smckusick #define OP_MASK 0x08 18651898Smckusick #define OP_NET 0x10 18751898Smckusick #define OP_ISO 0x20 18851898Smckusick #define OP_ALLDIRS 0x40 18951898Smckusick 19038460Smckusick #ifdef DEBUG 19138460Smckusick int debug = 1; 19251711Smckusick void SYSLOG __P((int, const char *, ...)); 19351711Smckusick #define syslog SYSLOG 19438460Smckusick #else 19538460Smckusick int debug = 0; 19638460Smckusick #endif 19738460Smckusick 19838460Smckusick /* 19938460Smckusick * Mountd server for NFS mount protocol as described in: 20039681Smckusick * NFS: Network File System Protocol Specification, RFC1094, Appendix A 20144015Smckusick * The optional arguments are the exports file name 20239681Smckusick * default: _PATH_EXPORTS 20344015Smckusick * and "-n" to allow nonroot mount. 20438460Smckusick */ 20566163Spendry int 20638460Smckusick main(argc, argv) 20738460Smckusick int argc; 20844015Smckusick char **argv; 20938460Smckusick { 21038460Smckusick SVCXPRT *transp; 21144015Smckusick int c; 21238460Smckusick 21344015Smckusick while ((c = getopt(argc, argv, "n")) != EOF) 21444015Smckusick switch (c) { 21544015Smckusick case 'n': 21667701Smckusick resvport_only = 0; 21744015Smckusick break; 21844015Smckusick default: 21944015Smckusick fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); 22044015Smckusick exit(1); 22144015Smckusick }; 22244015Smckusick argc -= optind; 22344015Smckusick argv += optind; 22466163Spendry grphead = (struct grouplist *)NULL; 22566163Spendry exphead = (struct exportlist *)NULL; 22666163Spendry mlhead = (struct mountlist *)NULL; 22744015Smckusick if (argc == 1) { 22844015Smckusick strncpy(exname, *argv, MAXPATHLEN-1); 22944015Smckusick exname[MAXPATHLEN-1] = '\0'; 23044015Smckusick } else 23144015Smckusick strcpy(exname, _PATH_EXPORTS); 23266163Spendry openlog("mountd", LOG_PID, LOG_DAEMON); 23351667Smckusick if (debug) 23451667Smckusick fprintf(stderr,"Getting export list.\n"); 23544015Smckusick get_exportlist(); 23651667Smckusick if (debug) 23751667Smckusick fprintf(stderr,"Getting mount list.\n"); 23844015Smckusick get_mountlist(); 23951667Smckusick if (debug) 24051667Smckusick fprintf(stderr,"Here we go.\n"); 24138460Smckusick if (debug == 0) { 24244690Skarels daemon(0, 0); 24338460Smckusick signal(SIGINT, SIG_IGN); 24438460Smckusick signal(SIGQUIT, SIG_IGN); 24538460Smckusick } 24666163Spendry signal(SIGHUP, (void (*) __P((int))) get_exportlist); 24766163Spendry signal(SIGTERM, (void (*) __P((int))) send_umntall); 24840494Smckusick { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 24940494Smckusick if (pidfile != NULL) { 25040494Smckusick fprintf(pidfile, "%d\n", getpid()); 25140494Smckusick fclose(pidfile); 25240494Smckusick } 25340494Smckusick } 25438460Smckusick if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { 25538460Smckusick syslog(LOG_ERR, "Can't create socket"); 25638460Smckusick exit(1); 25738460Smckusick } 25838460Smckusick pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 25951667Smckusick if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 26051667Smckusick IPPROTO_UDP)) { 26138460Smckusick syslog(LOG_ERR, "Can't register mount"); 26238460Smckusick exit(1); 26338460Smckusick } 26438460Smckusick svc_run(); 26538460Smckusick syslog(LOG_ERR, "Mountd died"); 26644690Skarels exit(1); 26738460Smckusick } 26838460Smckusick 26938460Smckusick /* 27038460Smckusick * The mount rpc service 27138460Smckusick */ 27266163Spendry void 27338460Smckusick mntsrv(rqstp, transp) 27466163Spendry struct svc_req *rqstp; 27566163Spendry SVCXPRT *transp; 27638460Smckusick { 27766163Spendry struct exportlist *ep; 27866163Spendry struct dirlist *dp; 27938460Smckusick nfsv2fh_t nfh; 28038460Smckusick struct stat stb; 28151898Smckusick struct statfs fsb; 28238460Smckusick struct hostent *hp; 28339681Smckusick u_long saddr; 28467701Smckusick u_short sport; 28551667Smckusick char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; 28651898Smckusick int bad = ENOENT, omask, defset; 28738460Smckusick 28839681Smckusick saddr = transp->xp_raddr.sin_addr.s_addr; 28967701Smckusick sport = ntohs(transp->xp_raddr.sin_port); 29066163Spendry hp = (struct hostent *)NULL; 29138460Smckusick switch (rqstp->rq_proc) { 29239681Smckusick case NULLPROC: 29366163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 29439681Smckusick syslog(LOG_ERR, "Can't send reply"); 29539681Smckusick return; 29638460Smckusick case RPCMNT_MOUNT: 29767701Smckusick if (sport >= IPPORT_RESERVED && resvport_only) { 29839681Smckusick svcerr_weakauth(transp); 29939681Smckusick return; 30039681Smckusick } 30151667Smckusick if (!svc_getargs(transp, xdr_dir, rpcpath)) { 30238460Smckusick svcerr_decode(transp); 30338460Smckusick return; 30438460Smckusick } 30538460Smckusick 30651667Smckusick /* 30767701Smckusick * Get the real pathname and make sure it is a file or 30867701Smckusick * directory that exists. 30951667Smckusick */ 31051898Smckusick if (realpath(rpcpath, dirpath) == 0 || 31151898Smckusick stat(dirpath, &stb) < 0 || 31267383Smkm (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) || 31351898Smckusick statfs(dirpath, &fsb) < 0) { 31451667Smckusick chdir("/"); /* Just in case realpath doesn't */ 31551667Smckusick if (debug) 31651898Smckusick fprintf(stderr, "stat failed on %s\n", dirpath); 31738460Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 31838460Smckusick syslog(LOG_ERR, "Can't send reply"); 31938460Smckusick return; 32038460Smckusick } 32138460Smckusick 32238460Smckusick /* Check in the exports list */ 32338460Smckusick omask = sigblock(sigmask(SIGHUP)); 32451898Smckusick ep = ex_search(&fsb.f_fsid); 32551898Smckusick defset = 0; 32651898Smckusick if (ep && (chk_host(ep->ex_defdir, saddr, &defset) || 32751898Smckusick ((dp = dirp_search(ep->ex_dirl, dirpath)) && 32851898Smckusick chk_host(dp, saddr, &defset)) || 32951898Smckusick (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 33051898Smckusick scan_tree(ep->ex_dirl, saddr) == 0))) { 33151667Smckusick /* Get the file handle */ 33251667Smckusick bzero((caddr_t)&nfh, sizeof(nfh)); 33351667Smckusick if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { 33451667Smckusick bad = errno; 33551898Smckusick syslog(LOG_ERR, "Can't get fh for %s", dirpath); 33651667Smckusick if (!svc_sendreply(transp, xdr_long, 33751667Smckusick (caddr_t)&bad)) 33851667Smckusick syslog(LOG_ERR, "Can't send reply"); 33951667Smckusick sigsetmask(omask); 34051667Smckusick return; 34151667Smckusick } 34251667Smckusick if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) 34338460Smckusick syslog(LOG_ERR, "Can't send reply"); 34451667Smckusick if (hp == NULL) 34551667Smckusick hp = gethostbyaddr((caddr_t)&saddr, 34651667Smckusick sizeof(saddr), AF_INET); 34751667Smckusick if (hp) 34851667Smckusick add_mlist(hp->h_name, dirpath); 34951667Smckusick else 35051667Smckusick add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 35151667Smckusick dirpath); 35251667Smckusick if (debug) 35351667Smckusick fprintf(stderr,"Mount successfull.\n"); 35451898Smckusick } else { 35551898Smckusick bad = EACCES; 35651898Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 35751898Smckusick syslog(LOG_ERR, "Can't send reply"); 35838460Smckusick } 35951667Smckusick sigsetmask(omask); 36038460Smckusick return; 36138460Smckusick case RPCMNT_DUMP: 36266163Spendry if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) 36338460Smckusick syslog(LOG_ERR, "Can't send reply"); 36438460Smckusick return; 36538460Smckusick case RPCMNT_UMOUNT: 36667701Smckusick if (sport >= IPPORT_RESERVED && resvport_only) { 36739681Smckusick svcerr_weakauth(transp); 36839681Smckusick return; 36939681Smckusick } 37038460Smckusick if (!svc_getargs(transp, xdr_dir, dirpath)) { 37138460Smckusick svcerr_decode(transp); 37238460Smckusick return; 37338460Smckusick } 37466163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 37538460Smckusick syslog(LOG_ERR, "Can't send reply"); 37644015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 37744015Smckusick if (hp) 37844015Smckusick del_mlist(hp->h_name, dirpath); 37951667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 38038460Smckusick return; 38138460Smckusick case RPCMNT_UMNTALL: 38267701Smckusick if (sport >= IPPORT_RESERVED && resvport_only) { 38339681Smckusick svcerr_weakauth(transp); 38439681Smckusick return; 38539681Smckusick } 38666163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 38738460Smckusick syslog(LOG_ERR, "Can't send reply"); 38844015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 38944015Smckusick if (hp) 39066163Spendry del_mlist(hp->h_name, (char *)NULL); 39166163Spendry del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL); 39238460Smckusick return; 39338460Smckusick case RPCMNT_EXPORT: 39466163Spendry if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) 39538460Smckusick syslog(LOG_ERR, "Can't send reply"); 39638460Smckusick return; 39738460Smckusick default: 39838460Smckusick svcerr_noproc(transp); 39938460Smckusick return; 40038460Smckusick } 40138460Smckusick } 40238460Smckusick 40338460Smckusick /* 40438460Smckusick * Xdr conversion for a dirpath string 40538460Smckusick */ 40666163Spendry int 40738460Smckusick xdr_dir(xdrsp, dirp) 40838460Smckusick XDR *xdrsp; 40938460Smckusick char *dirp; 41038460Smckusick { 41138460Smckusick return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 41238460Smckusick } 41338460Smckusick 41438460Smckusick /* 41538460Smckusick * Xdr routine to generate fhstatus 41638460Smckusick */ 41766163Spendry int 41838460Smckusick xdr_fhs(xdrsp, nfh) 41938460Smckusick XDR *xdrsp; 42038460Smckusick nfsv2fh_t *nfh; 42138460Smckusick { 42238460Smckusick int ok = 0; 42338460Smckusick 42438460Smckusick if (!xdr_long(xdrsp, &ok)) 42538460Smckusick return (0); 42638460Smckusick return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); 42738460Smckusick } 42838460Smckusick 42966163Spendry int 43038460Smckusick xdr_mlist(xdrsp, cp) 43138460Smckusick XDR *xdrsp; 43238460Smckusick caddr_t cp; 43338460Smckusick { 43466163Spendry struct mountlist *mlp; 43538460Smckusick int true = 1; 43638460Smckusick int false = 0; 43738460Smckusick char *strp; 43838460Smckusick 43944015Smckusick mlp = mlhead; 44044015Smckusick while (mlp) { 44144015Smckusick if (!xdr_bool(xdrsp, &true)) 44244015Smckusick return (0); 44344015Smckusick strp = &mlp->ml_host[0]; 44444015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 44544015Smckusick return (0); 44644015Smckusick strp = &mlp->ml_dirp[0]; 44744015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 44844015Smckusick return (0); 44944015Smckusick mlp = mlp->ml_next; 45038460Smckusick } 45138460Smckusick if (!xdr_bool(xdrsp, &false)) 45238460Smckusick return (0); 45338460Smckusick return (1); 45438460Smckusick } 45538460Smckusick 45638460Smckusick /* 45738460Smckusick * Xdr conversion for export list 45838460Smckusick */ 45966163Spendry int 46038460Smckusick xdr_explist(xdrsp, cp) 46138460Smckusick XDR *xdrsp; 46238460Smckusick caddr_t cp; 46338460Smckusick { 46466163Spendry struct exportlist *ep; 46538460Smckusick int false = 0; 46664903Smckusick int omask, putdef; 46738460Smckusick 46838460Smckusick omask = sigblock(sigmask(SIGHUP)); 46951898Smckusick ep = exphead; 47051898Smckusick while (ep) { 47164903Smckusick putdef = 0; 47264903Smckusick if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 47338460Smckusick goto errout; 47464903Smckusick if (ep->ex_defdir && putdef == 0 && 47566163Spendry put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 47664903Smckusick &putdef)) 47764903Smckusick goto errout; 47838460Smckusick ep = ep->ex_next; 47938460Smckusick } 48038460Smckusick sigsetmask(omask); 48138460Smckusick if (!xdr_bool(xdrsp, &false)) 48238460Smckusick return (0); 48338460Smckusick return (1); 48438460Smckusick errout: 48538460Smckusick sigsetmask(omask); 48638460Smckusick return (0); 48738460Smckusick } 48838460Smckusick 48951898Smckusick /* 49051898Smckusick * Called from xdr_explist() to traverse the tree and export the 49151898Smckusick * directory paths. 49251898Smckusick */ 49366163Spendry int 49464903Smckusick put_exlist(dp, xdrsp, adp, putdefp) 49566163Spendry struct dirlist *dp; 49651898Smckusick XDR *xdrsp; 49751898Smckusick struct dirlist *adp; 49864903Smckusick int *putdefp; 49951898Smckusick { 50066163Spendry struct grouplist *grp; 50166163Spendry struct hostlist *hp; 50251898Smckusick int true = 1; 50351898Smckusick int false = 0; 50451898Smckusick int gotalldir = 0; 50551898Smckusick char *strp; 50651898Smckusick 50751898Smckusick if (dp) { 50864903Smckusick if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 50951898Smckusick return (1); 51051898Smckusick if (!xdr_bool(xdrsp, &true)) 51151898Smckusick return (1); 51251898Smckusick strp = dp->dp_dirp; 51351898Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 51451898Smckusick return (1); 51564903Smckusick if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 51651898Smckusick gotalldir = 1; 51764903Smckusick *putdefp = 1; 51864903Smckusick } 51951898Smckusick if ((dp->dp_flag & DP_DEFSET) == 0 && 52051898Smckusick (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 52151898Smckusick hp = dp->dp_hosts; 52251898Smckusick while (hp) { 52351898Smckusick grp = hp->ht_grp; 52451898Smckusick if (grp->gr_type == GT_HOST) { 52551898Smckusick if (!xdr_bool(xdrsp, &true)) 52651898Smckusick return (1); 52751898Smckusick strp = grp->gr_ptr.gt_hostent->h_name; 52851898Smckusick if (!xdr_string(xdrsp, &strp, 52951898Smckusick RPCMNT_NAMELEN)) 53051898Smckusick return (1); 53151898Smckusick } else if (grp->gr_type == GT_NET) { 53251898Smckusick if (!xdr_bool(xdrsp, &true)) 53351898Smckusick return (1); 53451898Smckusick strp = grp->gr_ptr.gt_net.nt_name; 53551898Smckusick if (!xdr_string(xdrsp, &strp, 53651898Smckusick RPCMNT_NAMELEN)) 53751898Smckusick return (1); 53851898Smckusick } 53951898Smckusick hp = hp->ht_next; 54066163Spendry if (gotalldir && hp == (struct hostlist *)NULL) { 54151898Smckusick hp = adp->dp_hosts; 54251898Smckusick gotalldir = 0; 54351898Smckusick } 54451898Smckusick } 54551898Smckusick } 54651898Smckusick if (!xdr_bool(xdrsp, &false)) 54751898Smckusick return (1); 54864903Smckusick if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 54951898Smckusick return (1); 55051898Smckusick } 55151898Smckusick return (0); 55251898Smckusick } 55351898Smckusick 55438460Smckusick #define LINESIZ 10240 55538460Smckusick char line[LINESIZ]; 55651898Smckusick FILE *exp_file; 55738460Smckusick 55838460Smckusick /* 55938460Smckusick * Get the export list 56038460Smckusick */ 56146709Sbostic void 56238460Smckusick get_exportlist() 56338460Smckusick { 56466163Spendry struct exportlist *ep, *ep2; 56566163Spendry struct grouplist *grp, *tgrp; 56651898Smckusick struct exportlist **epp; 56751898Smckusick struct dirlist *dirhead; 56852109Smckusick struct statfs fsb, *fsp; 56951898Smckusick struct hostent *hpe; 57051898Smckusick struct ucred anon; 57153150Smckusick char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 57253150Smckusick int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 57338460Smckusick 57438460Smckusick /* 57538460Smckusick * First, get rid of the old list 57638460Smckusick */ 57751898Smckusick ep = exphead; 57851898Smckusick while (ep) { 57938460Smckusick ep2 = ep; 58038460Smckusick ep = ep->ex_next; 58144015Smckusick free_exp(ep2); 58238460Smckusick } 58366163Spendry exphead = (struct exportlist *)NULL; 58438460Smckusick 58551898Smckusick grp = grphead; 58651898Smckusick while (grp) { 58751898Smckusick tgrp = grp; 58851898Smckusick grp = grp->gr_next; 58951898Smckusick free_grp(tgrp); 59051667Smckusick } 59166163Spendry grphead = (struct grouplist *)NULL; 59251667Smckusick 59338460Smckusick /* 59452109Smckusick * And delete exports that are in the kernel for all local 59552109Smckusick * file systems. 59652109Smckusick * XXX: Should know how to handle all local exportable file systems 59752109Smckusick * instead of just MOUNT_UFS. 59852109Smckusick */ 59953214Smckusick num = getmntinfo(&fsp, MNT_NOWAIT); 60052109Smckusick for (i = 0; i < num; i++) { 60165713Shibler union { 60265713Shibler struct ufs_args ua; 60365713Shibler struct iso_args ia; 60465713Shibler struct mfs_args ma; 60565713Shibler } targs; 60665713Shibler 60765713Shibler switch (fsp->f_type) { 60865863Sbostic case MOUNT_MFS: 60965713Shibler case MOUNT_UFS: 61065863Sbostic case MOUNT_CD9660: 61165863Sbostic targs.ua.fspec = NULL; 61265713Shibler targs.ua.export.ex_flags = MNT_DELEXPORT; 61352109Smckusick if (mount(fsp->f_type, fsp->f_mntonname, 61465713Shibler fsp->f_flags | MNT_UPDATE, 61565713Shibler (caddr_t)&targs) < 0) 61665713Shibler syslog(LOG_ERR, "Can't delete exports for %s", 61752109Smckusick fsp->f_mntonname); 61852109Smckusick } 61952109Smckusick fsp++; 62052109Smckusick } 62152109Smckusick 62252109Smckusick /* 62338460Smckusick * Read in the exports file and build the list, calling 62451667Smckusick * mount() as we go along to push the export rules into the kernel. 62538460Smckusick */ 62651898Smckusick if ((exp_file = fopen(exname, "r")) == NULL) { 62738460Smckusick syslog(LOG_ERR, "Can't open %s", exname); 62838460Smckusick exit(2); 62938460Smckusick } 63066163Spendry dirhead = (struct dirlist *)NULL; 63151898Smckusick while (get_line()) { 63251667Smckusick if (debug) 63351667Smckusick fprintf(stderr,"Got line %s\n",line); 63438460Smckusick cp = line; 63538460Smckusick nextfield(&cp, &endcp); 63651667Smckusick if (*cp == '#') 63751667Smckusick goto nextline; 63851898Smckusick 63951898Smckusick /* 64051898Smckusick * Set defaults. 64151898Smckusick */ 64251898Smckusick has_host = FALSE; 64351898Smckusick anon = def_anon; 64451667Smckusick exflags = MNT_EXPORTED; 64551898Smckusick got_nondir = 0; 64651898Smckusick opt_flags = 0; 64766163Spendry ep = (struct exportlist *)NULL; 64844015Smckusick 64944015Smckusick /* 65044015Smckusick * Create new exports list entry 65144015Smckusick */ 65238460Smckusick len = endcp-cp; 65353150Smckusick tgrp = grp = get_grp(); 65451898Smckusick while (len > 0) { 65551898Smckusick if (len > RPCMNT_NAMELEN) { 65653150Smckusick getexp_err(ep, tgrp); 65751898Smckusick goto nextline; 65851667Smckusick } 65945271Smckusick if (*cp == '-') { 66066163Spendry if (ep == (struct exportlist *)NULL) { 66153150Smckusick getexp_err(ep, tgrp); 66251898Smckusick goto nextline; 66351898Smckusick } 66451898Smckusick if (debug) 66551898Smckusick fprintf(stderr, "doing opt %s\n", cp); 66651898Smckusick got_nondir = 1; 66751898Smckusick if (do_opt(&cp, &endcp, ep, grp, &has_host, 66851898Smckusick &exflags, &anon)) { 66953150Smckusick getexp_err(ep, tgrp); 67051898Smckusick goto nextline; 67151898Smckusick } 67251898Smckusick } else if (*cp == '/') { 67351898Smckusick savedc = *endcp; 67451898Smckusick *endcp = '\0'; 67565940Sbostic if (check_dirpath(cp) && 67651898Smckusick statfs(cp, &fsb) >= 0) { 67751898Smckusick if (got_nondir) { 67851898Smckusick syslog(LOG_ERR, "Dirs must be first"); 67953150Smckusick getexp_err(ep, tgrp); 68051898Smckusick goto nextline; 68151898Smckusick } 68251898Smckusick if (ep) { 68351898Smckusick if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 68451898Smckusick ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 68553150Smckusick getexp_err(ep, tgrp); 68651898Smckusick goto nextline; 68751898Smckusick } 68851667Smckusick } else { 68951898Smckusick /* 69051898Smckusick * See if this directory is already 69151898Smckusick * in the list. 69251898Smckusick */ 69351898Smckusick ep = ex_search(&fsb.f_fsid); 69466163Spendry if (ep == (struct exportlist *)NULL) { 69551898Smckusick ep = get_exp(); 69651898Smckusick ep->ex_fs = fsb.f_fsid; 69751898Smckusick ep->ex_fsdir = (char *) 69851898Smckusick malloc(strlen(fsb.f_mntonname) + 1); 69951898Smckusick if (ep->ex_fsdir) 70051898Smckusick strcpy(ep->ex_fsdir, 70151898Smckusick fsb.f_mntonname); 70251898Smckusick else 70351898Smckusick out_of_mem(); 70451898Smckusick if (debug) 70551898Smckusick fprintf(stderr, 70651898Smckusick "Making new ep fs=0x%x,0x%x\n", 70751898Smckusick fsb.f_fsid.val[0], 70851898Smckusick fsb.f_fsid.val[1]); 70951898Smckusick } else if (debug) 71051898Smckusick fprintf(stderr, 71151898Smckusick "Found ep fs=0x%x,0x%x\n", 71251898Smckusick fsb.f_fsid.val[0], 71351898Smckusick fsb.f_fsid.val[1]); 71438460Smckusick } 71551898Smckusick 71651898Smckusick /* 71751898Smckusick * Add dirpath to export mount point. 71851898Smckusick */ 71951898Smckusick dirp = add_expdir(&dirhead, cp, len); 72051898Smckusick dirplen = len; 72151898Smckusick } else { 72253150Smckusick getexp_err(ep, tgrp); 72351898Smckusick goto nextline; 72451898Smckusick } 72551898Smckusick *endcp = savedc; 72651898Smckusick } else { 72751898Smckusick savedc = *endcp; 72851898Smckusick *endcp = '\0'; 72951898Smckusick got_nondir = 1; 73066163Spendry if (ep == (struct exportlist *)NULL) { 73153150Smckusick getexp_err(ep, tgrp); 73251898Smckusick goto nextline; 73351898Smckusick } 73453150Smckusick 73553150Smckusick /* 73653150Smckusick * Get the host or netgroup. 73753150Smckusick */ 73853150Smckusick setnetgrent(cp); 73953150Smckusick netgrp = getnetgrent(&hst, &usr, &dom); 74053150Smckusick do { 74153150Smckusick if (has_host) { 74253150Smckusick grp->gr_next = get_grp(); 74353150Smckusick grp = grp->gr_next; 74453150Smckusick } 74553150Smckusick if (netgrp) { 74653150Smckusick if (get_host(hst, grp)) { 74753150Smckusick syslog(LOG_ERR, "Bad netgroup %s", cp); 74853150Smckusick getexp_err(ep, tgrp); 749*68095Shibler endnetgrent(); 75053150Smckusick goto nextline; 75153150Smckusick } 75253150Smckusick } else if (get_host(cp, grp)) { 75353150Smckusick getexp_err(ep, tgrp); 75453150Smckusick goto nextline; 75553150Smckusick } 75653150Smckusick has_host = TRUE; 75753150Smckusick } while (netgrp && getnetgrent(&hst, &usr, &dom)); 75853150Smckusick endnetgrent(); 75951898Smckusick *endcp = savedc; 76038460Smckusick } 76138460Smckusick cp = endcp; 76238460Smckusick nextfield(&cp, &endcp); 76345271Smckusick len = endcp - cp; 76438460Smckusick } 76551898Smckusick if (check_options(dirhead)) { 76653150Smckusick getexp_err(ep, tgrp); 76751898Smckusick goto nextline; 76851898Smckusick } 76951898Smckusick if (!has_host) { 77051898Smckusick grp->gr_type = GT_HOST; 77151667Smckusick if (debug) 77251667Smckusick fprintf(stderr,"Adding a default entry\n"); 77351667Smckusick /* add a default group and make the grp list NULL */ 77451667Smckusick hpe = (struct hostent *)malloc(sizeof(struct hostent)); 77566163Spendry if (hpe == (struct hostent *)NULL) 77651898Smckusick out_of_mem(); 77751898Smckusick hpe->h_name = "Default"; 77851667Smckusick hpe->h_addrtype = AF_INET; 77951667Smckusick hpe->h_length = sizeof (u_long); 78066163Spendry hpe->h_addr_list = (char **)NULL; 78151898Smckusick grp->gr_ptr.gt_hostent = hpe; 78253150Smckusick 78353150Smckusick /* 78453150Smckusick * Don't allow a network export coincide with a list of 78553150Smckusick * host(s) on the same line. 78653150Smckusick */ 78753150Smckusick } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 78853150Smckusick getexp_err(ep, tgrp); 78953150Smckusick goto nextline; 79051667Smckusick } 79153150Smckusick 79253150Smckusick /* 79353150Smckusick * Loop through hosts, pushing the exports into the kernel. 79453150Smckusick * After loop, tgrp points to the start of the list and 79553150Smckusick * grp points to the last entry in the list. 79653150Smckusick */ 79753150Smckusick grp = tgrp; 79853150Smckusick do { 79953150Smckusick if (do_mount(ep, grp, exflags, &anon, dirp, 80051898Smckusick dirplen, &fsb)) { 80153150Smckusick getexp_err(ep, tgrp); 80251898Smckusick goto nextline; 80353150Smckusick } 80453150Smckusick } while (grp->gr_next && (grp = grp->gr_next)); 80551898Smckusick 80651898Smckusick /* 80751898Smckusick * Success. Update the data structures. 80851898Smckusick */ 80951898Smckusick if (has_host) { 81053150Smckusick hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS)); 81151898Smckusick grp->gr_next = grphead; 81253150Smckusick grphead = tgrp; 81351898Smckusick } else { 81466163Spendry hang_dirp(dirhead, (struct grouplist *)NULL, ep, 81553150Smckusick (opt_flags & OP_ALLDIRS)); 81651898Smckusick free_grp(grp); 81751898Smckusick } 81866163Spendry dirhead = (struct dirlist *)NULL; 81951898Smckusick if ((ep->ex_flag & EX_LINKED) == 0) { 82051898Smckusick ep2 = exphead; 82151898Smckusick epp = &exphead; 82251898Smckusick 82351898Smckusick /* 82451898Smckusick * Insert in the list in alphabetical order. 82551898Smckusick */ 82651898Smckusick while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 82751898Smckusick epp = &ep2->ex_next; 82851898Smckusick ep2 = ep2->ex_next; 82951898Smckusick } 83051898Smckusick if (ep2) 83151898Smckusick ep->ex_next = ep2; 83251898Smckusick *epp = ep; 83351898Smckusick ep->ex_flag |= EX_LINKED; 83451898Smckusick } 83551898Smckusick nextline: 83651898Smckusick if (dirhead) { 83751898Smckusick free_dir(dirhead); 83866163Spendry dirhead = (struct dirlist *)NULL; 83951898Smckusick } 84051898Smckusick } 84151898Smckusick fclose(exp_file); 84251898Smckusick } 84351898Smckusick 84451898Smckusick /* 84551898Smckusick * Allocate an export list element 84651898Smckusick */ 84751898Smckusick struct exportlist * 84851898Smckusick get_exp() 84951898Smckusick { 85066163Spendry struct exportlist *ep; 85151898Smckusick 85251898Smckusick ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 85366163Spendry if (ep == (struct exportlist *)NULL) 85451898Smckusick out_of_mem(); 85551898Smckusick bzero((caddr_t)ep, sizeof (struct exportlist)); 85651898Smckusick return (ep); 85751898Smckusick } 85851898Smckusick 85951898Smckusick /* 86051898Smckusick * Allocate a group list element 86151898Smckusick */ 86251898Smckusick struct grouplist * 86351898Smckusick get_grp() 86451898Smckusick { 86566163Spendry struct grouplist *gp; 86651898Smckusick 86751898Smckusick gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 86866163Spendry if (gp == (struct grouplist *)NULL) 86951898Smckusick out_of_mem(); 87051898Smckusick bzero((caddr_t)gp, sizeof (struct grouplist)); 87151898Smckusick return (gp); 87251898Smckusick } 87351898Smckusick 87451898Smckusick /* 87551898Smckusick * Clean up upon an error in get_exportlist(). 87651898Smckusick */ 87751898Smckusick void 87851898Smckusick getexp_err(ep, grp) 87951898Smckusick struct exportlist *ep; 88051898Smckusick struct grouplist *grp; 88151898Smckusick { 88253150Smckusick struct grouplist *tgrp; 88351898Smckusick 88451898Smckusick syslog(LOG_ERR, "Bad exports list line %s", line); 88559017Smckusick if (ep && (ep->ex_flag & EX_LINKED) == 0) 88651898Smckusick free_exp(ep); 88753150Smckusick while (grp) { 88853150Smckusick tgrp = grp; 88953150Smckusick grp = grp->gr_next; 89053150Smckusick free_grp(tgrp); 89153150Smckusick } 89251898Smckusick } 89351898Smckusick 89451898Smckusick /* 89551898Smckusick * Search the export list for a matching fs. 89651898Smckusick */ 89751898Smckusick struct exportlist * 89851898Smckusick ex_search(fsid) 89952109Smckusick fsid_t *fsid; 90051898Smckusick { 90166163Spendry struct exportlist *ep; 90251898Smckusick 90351898Smckusick ep = exphead; 90451898Smckusick while (ep) { 90551898Smckusick if (ep->ex_fs.val[0] == fsid->val[0] && 90651898Smckusick ep->ex_fs.val[1] == fsid->val[1]) 90751898Smckusick return (ep); 90851898Smckusick ep = ep->ex_next; 90951898Smckusick } 91051898Smckusick return (ep); 91151898Smckusick } 91251898Smckusick 91351898Smckusick /* 91451898Smckusick * Add a directory path to the list. 91551898Smckusick */ 91651898Smckusick char * 91751898Smckusick add_expdir(dpp, cp, len) 91851898Smckusick struct dirlist **dpp; 91951898Smckusick char *cp; 92051898Smckusick int len; 92151898Smckusick { 92266163Spendry struct dirlist *dp; 92351898Smckusick 92451898Smckusick dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 92551898Smckusick dp->dp_left = *dpp; 92666163Spendry dp->dp_right = (struct dirlist *)NULL; 92751898Smckusick dp->dp_flag = 0; 92866163Spendry dp->dp_hosts = (struct hostlist *)NULL; 92951898Smckusick strcpy(dp->dp_dirp, cp); 93051898Smckusick *dpp = dp; 93151898Smckusick return (dp->dp_dirp); 93251898Smckusick } 93351898Smckusick 93451898Smckusick /* 93551898Smckusick * Hang the dir list element off the dirpath binary tree as required 93651898Smckusick * and update the entry for host. 93751898Smckusick */ 93851898Smckusick void 93951898Smckusick hang_dirp(dp, grp, ep, alldirs) 94066163Spendry struct dirlist *dp; 94151898Smckusick struct grouplist *grp; 94251898Smckusick struct exportlist *ep; 94351898Smckusick int alldirs; 94451898Smckusick { 94566163Spendry struct hostlist *hp; 94651898Smckusick struct dirlist *dp2; 94751898Smckusick 94851898Smckusick if (alldirs) { 94951898Smckusick if (ep->ex_defdir) 95051898Smckusick free((caddr_t)dp); 95151898Smckusick else 95251898Smckusick ep->ex_defdir = dp; 95366163Spendry if (grp == (struct grouplist *)NULL) 95455292Smckusick ep->ex_defdir->dp_flag |= DP_DEFSET; 95555292Smckusick else while (grp) { 95651898Smckusick hp = get_ht(); 95751898Smckusick hp->ht_grp = grp; 95851898Smckusick hp->ht_next = ep->ex_defdir->dp_hosts; 95951898Smckusick ep->ex_defdir->dp_hosts = hp; 96055292Smckusick grp = grp->gr_next; 96155292Smckusick } 96251898Smckusick } else { 96353150Smckusick 96453150Smckusick /* 96553150Smckusick * Loop throught the directories adding them to the tree. 96653150Smckusick */ 96751898Smckusick while (dp) { 96851898Smckusick dp2 = dp->dp_left; 96953150Smckusick add_dlist(&ep->ex_dirl, dp, grp); 97051898Smckusick dp = dp2; 97151898Smckusick } 97251898Smckusick } 97351898Smckusick } 97451898Smckusick 97551898Smckusick /* 97651898Smckusick * Traverse the binary tree either updating a node that is already there 97751898Smckusick * for the new directory or adding the new node. 97851898Smckusick */ 97951898Smckusick void 98053150Smckusick add_dlist(dpp, newdp, grp) 98151898Smckusick struct dirlist **dpp; 98251898Smckusick struct dirlist *newdp; 98366163Spendry struct grouplist *grp; 98451898Smckusick { 98566163Spendry struct dirlist *dp; 98666163Spendry struct hostlist *hp; 98751898Smckusick int cmp; 98851898Smckusick 98951898Smckusick dp = *dpp; 99051898Smckusick if (dp) { 99151898Smckusick cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 99251898Smckusick if (cmp > 0) { 99353150Smckusick add_dlist(&dp->dp_left, newdp, grp); 99451898Smckusick return; 99551898Smckusick } else if (cmp < 0) { 99653150Smckusick add_dlist(&dp->dp_right, newdp, grp); 99751898Smckusick return; 99851898Smckusick } else 99951898Smckusick free((caddr_t)newdp); 100051898Smckusick } else { 100151898Smckusick dp = newdp; 100266163Spendry dp->dp_left = (struct dirlist *)NULL; 100351898Smckusick *dpp = dp; 100451898Smckusick } 100553150Smckusick if (grp) { 100653150Smckusick 100753150Smckusick /* 100853150Smckusick * Hang all of the host(s) off of the directory point. 100953150Smckusick */ 101053150Smckusick do { 101153150Smckusick hp = get_ht(); 101253150Smckusick hp->ht_grp = grp; 101353150Smckusick hp->ht_next = dp->dp_hosts; 101453150Smckusick dp->dp_hosts = hp; 101553150Smckusick grp = grp->gr_next; 101653150Smckusick } while (grp); 101751898Smckusick } else 101851898Smckusick dp->dp_flag |= DP_DEFSET; 101951898Smckusick } 102051898Smckusick 102151898Smckusick /* 102251898Smckusick * Search for a dirpath on the export point. 102351898Smckusick */ 102451898Smckusick struct dirlist * 102551898Smckusick dirp_search(dp, dirpath) 102666163Spendry struct dirlist *dp; 102751898Smckusick char *dirpath; 102851898Smckusick { 102966163Spendry int cmp; 103051898Smckusick 103151898Smckusick if (dp) { 103251898Smckusick cmp = strcmp(dp->dp_dirp, dirpath); 103351898Smckusick if (cmp > 0) 103451898Smckusick return (dirp_search(dp->dp_left, dirpath)); 103551898Smckusick else if (cmp < 0) 103651898Smckusick return (dirp_search(dp->dp_right, dirpath)); 103751898Smckusick else 103851898Smckusick return (dp); 103951898Smckusick } 104051898Smckusick return (dp); 104151898Smckusick } 104251898Smckusick 104351898Smckusick /* 104451898Smckusick * Scan for a host match in a directory tree. 104551898Smckusick */ 104666163Spendry int 104751898Smckusick chk_host(dp, saddr, defsetp) 104851898Smckusick struct dirlist *dp; 104951898Smckusick u_long saddr; 105051898Smckusick int *defsetp; 105151898Smckusick { 105266163Spendry struct hostlist *hp; 105366163Spendry struct grouplist *grp; 105466163Spendry u_long **addrp; 105551898Smckusick 105651898Smckusick if (dp) { 105751898Smckusick if (dp->dp_flag & DP_DEFSET) 105851898Smckusick *defsetp = 1; 105951898Smckusick hp = dp->dp_hosts; 106051898Smckusick while (hp) { 106151898Smckusick grp = hp->ht_grp; 106251898Smckusick switch (grp->gr_type) { 106351898Smckusick case GT_HOST: 106451898Smckusick addrp = (u_long **) 106551898Smckusick grp->gr_ptr.gt_hostent->h_addr_list; 106651898Smckusick while (*addrp) { 106751898Smckusick if (**addrp == saddr) 106851898Smckusick return (1); 106951898Smckusick addrp++; 107051898Smckusick } 107151898Smckusick break; 107251898Smckusick case GT_NET: 107351898Smckusick if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 107451898Smckusick grp->gr_ptr.gt_net.nt_net) 107551898Smckusick return (1); 107651898Smckusick break; 107751898Smckusick }; 107851898Smckusick hp = hp->ht_next; 107951898Smckusick } 108051898Smckusick } 108151898Smckusick return (0); 108251898Smckusick } 108351898Smckusick 108451898Smckusick /* 108551898Smckusick * Scan tree for a host that matches the address. 108651898Smckusick */ 108766163Spendry int 108851898Smckusick scan_tree(dp, saddr) 108966163Spendry struct dirlist *dp; 109051898Smckusick u_long saddr; 109151898Smckusick { 109251898Smckusick int defset; 109351898Smckusick 109451898Smckusick if (dp) { 109551898Smckusick if (scan_tree(dp->dp_left, saddr)) 109651898Smckusick return (1); 109751898Smckusick if (chk_host(dp, saddr, &defset)) 109851898Smckusick return (1); 109951898Smckusick if (scan_tree(dp->dp_right, saddr)) 110051898Smckusick return (1); 110151898Smckusick } 110251898Smckusick return (0); 110351898Smckusick } 110451898Smckusick 110551898Smckusick /* 110651898Smckusick * Traverse the dirlist tree and free it up. 110751898Smckusick */ 110851898Smckusick void 110951898Smckusick free_dir(dp) 111066163Spendry struct dirlist *dp; 111151898Smckusick { 111251898Smckusick 111351898Smckusick if (dp) { 111451898Smckusick free_dir(dp->dp_left); 111551898Smckusick free_dir(dp->dp_right); 111651898Smckusick free_host(dp->dp_hosts); 111751898Smckusick free((caddr_t)dp); 111851898Smckusick } 111951898Smckusick } 112051898Smckusick 112151898Smckusick /* 112251898Smckusick * Parse the option string and update fields. 112351898Smckusick * Option arguments may either be -<option>=<value> or 112451898Smckusick * -<option> <value> 112551898Smckusick */ 112666163Spendry int 112751898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 112851898Smckusick char **cpp, **endcpp; 112951898Smckusick struct exportlist *ep; 113051898Smckusick struct grouplist *grp; 113151898Smckusick int *has_hostp; 113251898Smckusick int *exflagsp; 113351898Smckusick struct ucred *cr; 113451898Smckusick { 113566163Spendry char *cpoptarg, *cpoptend; 113651898Smckusick char *cp, *endcp, *cpopt, savedc, savedc2; 113751898Smckusick int allflag, usedarg; 113851898Smckusick 113951898Smckusick cpopt = *cpp; 114051898Smckusick cpopt++; 114151898Smckusick cp = *endcpp; 114251898Smckusick savedc = *cp; 114351898Smckusick *cp = '\0'; 114451898Smckusick while (cpopt && *cpopt) { 114551898Smckusick allflag = 1; 114651898Smckusick usedarg = -2; 114751898Smckusick if (cpoptend = index(cpopt, ',')) { 114851898Smckusick *cpoptend++ = '\0'; 114951898Smckusick if (cpoptarg = index(cpopt, '=')) 115051898Smckusick *cpoptarg++ = '\0'; 115151898Smckusick } else { 115251898Smckusick if (cpoptarg = index(cpopt, '=')) 115351898Smckusick *cpoptarg++ = '\0'; 115451898Smckusick else { 115551898Smckusick *cp = savedc; 115651898Smckusick nextfield(&cp, &endcp); 115751898Smckusick **endcpp = '\0'; 115851898Smckusick if (endcp > cp && *cp != '-') { 115951898Smckusick cpoptarg = cp; 116051898Smckusick savedc2 = *endcp; 116151898Smckusick *endcp = '\0'; 116251898Smckusick usedarg = 0; 116351667Smckusick } 116451667Smckusick } 116551667Smckusick } 116651898Smckusick if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 116751898Smckusick *exflagsp |= MNT_EXRDONLY; 116851898Smckusick } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 116951898Smckusick !(allflag = strcmp(cpopt, "mapall")) || 117051898Smckusick !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 117151898Smckusick usedarg++; 117251898Smckusick parsecred(cpoptarg, cr); 117351898Smckusick if (allflag == 0) { 117451898Smckusick *exflagsp |= MNT_EXPORTANON; 117551898Smckusick opt_flags |= OP_MAPALL; 117651898Smckusick } else 117751898Smckusick opt_flags |= OP_MAPROOT; 117851898Smckusick } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 117951898Smckusick *exflagsp |= MNT_EXKERB; 118051898Smckusick opt_flags |= OP_KERB; 118153150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "mask") || 118253150Smckusick !strcmp(cpopt, "m"))) { 118351898Smckusick if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 118451898Smckusick syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 118551898Smckusick return (1); 118651898Smckusick } 118751898Smckusick usedarg++; 118851898Smckusick opt_flags |= OP_MASK; 118953150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "network") || 119053150Smckusick !strcmp(cpopt, "n"))) { 119151898Smckusick if (grp->gr_type != GT_NULL) { 119251898Smckusick syslog(LOG_ERR, "Network/host conflict"); 119351898Smckusick return (1); 119451898Smckusick } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 119551898Smckusick syslog(LOG_ERR, "Bad net: %s", cpoptarg); 119651898Smckusick return (1); 119751898Smckusick } 119851898Smckusick grp->gr_type = GT_NET; 119951898Smckusick *has_hostp = 1; 120051898Smckusick usedarg++; 120151898Smckusick opt_flags |= OP_NET; 120251898Smckusick } else if (!strcmp(cpopt, "alldirs")) { 120351898Smckusick opt_flags |= OP_ALLDIRS; 120451898Smckusick #ifdef ISO 120551898Smckusick } else if (cpoptarg && !strcmp(cpopt, "iso")) { 120651898Smckusick if (get_isoaddr(cpoptarg, grp)) { 120751898Smckusick syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 120851898Smckusick return (1); 120951898Smckusick } 121051898Smckusick *has_hostp = 1; 121151898Smckusick usedarg++; 121251898Smckusick opt_flags |= OP_ISO; 121351898Smckusick #endif /* ISO */ 121451898Smckusick } else { 121551898Smckusick syslog(LOG_ERR, "Bad opt %s", cpopt); 121651898Smckusick return (1); 121751667Smckusick } 121851898Smckusick if (usedarg >= 0) { 121951898Smckusick *endcp = savedc2; 122051898Smckusick **endcpp = savedc; 122151898Smckusick if (usedarg > 0) { 122251898Smckusick *cpp = cp; 122351898Smckusick *endcpp = endcp; 122451898Smckusick } 122551898Smckusick return (0); 122651898Smckusick } 122751898Smckusick cpopt = cpoptend; 122851667Smckusick } 122951898Smckusick **endcpp = savedc; 123051898Smckusick return (0); 123151898Smckusick } 123251898Smckusick 123351898Smckusick /* 123451898Smckusick * Translate a character string to the corresponding list of network 123551898Smckusick * addresses for a hostname. 123651898Smckusick */ 123766163Spendry int 123851898Smckusick get_host(cp, grp) 123951898Smckusick char *cp; 124066163Spendry struct grouplist *grp; 124151898Smckusick { 124266163Spendry struct hostent *hp, *nhp; 124366163Spendry char **addrp, **naddrp; 124451898Smckusick struct hostent t_host; 124551898Smckusick int i; 124651898Smckusick u_long saddr; 124751898Smckusick char *aptr[2]; 124851898Smckusick 124951898Smckusick if (grp->gr_type != GT_NULL) 125051898Smckusick return (1); 125151898Smckusick if ((hp = gethostbyname(cp)) == NULL) { 125251898Smckusick if (isdigit(*cp)) { 125351898Smckusick saddr = inet_addr(cp); 125451898Smckusick if (saddr == -1) { 1255*68095Shibler syslog(LOG_ERR, "Inet_addr failed for %s", cp); 125651898Smckusick return (1); 125751898Smckusick } 125851898Smckusick if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 125951898Smckusick AF_INET)) == NULL) { 126051898Smckusick hp = &t_host; 126151898Smckusick hp->h_name = cp; 126251898Smckusick hp->h_addrtype = AF_INET; 126351898Smckusick hp->h_length = sizeof (u_long); 126451898Smckusick hp->h_addr_list = aptr; 126551898Smckusick aptr[0] = (char *)&saddr; 126666163Spendry aptr[1] = (char *)NULL; 126751898Smckusick } 126851898Smckusick } else { 1269*68095Shibler syslog(LOG_ERR, "Gethostbyname failed for %s", cp); 127051898Smckusick return (1); 127151898Smckusick } 127251898Smckusick } 127351898Smckusick grp->gr_type = GT_HOST; 127451898Smckusick nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 127551898Smckusick malloc(sizeof(struct hostent)); 127666163Spendry if (nhp == (struct hostent *)NULL) 127751898Smckusick out_of_mem(); 127851898Smckusick bcopy((caddr_t)hp, (caddr_t)nhp, 127951898Smckusick sizeof(struct hostent)); 128051898Smckusick i = strlen(hp->h_name)+1; 128151898Smckusick nhp->h_name = (char *)malloc(i); 128266163Spendry if (nhp->h_name == (char *)NULL) 128351898Smckusick out_of_mem(); 128451898Smckusick bcopy(hp->h_name, nhp->h_name, i); 128551898Smckusick addrp = hp->h_addr_list; 128651898Smckusick i = 1; 128751898Smckusick while (*addrp++) 128851898Smckusick i++; 128951898Smckusick naddrp = nhp->h_addr_list = (char **) 129051898Smckusick malloc(i*sizeof(char *)); 129166163Spendry if (naddrp == (char **)NULL) 129251898Smckusick out_of_mem(); 129351898Smckusick addrp = hp->h_addr_list; 129451898Smckusick while (*addrp) { 129551898Smckusick *naddrp = (char *) 129651898Smckusick malloc(hp->h_length); 129766163Spendry if (*naddrp == (char *)NULL) 129851898Smckusick out_of_mem(); 129951898Smckusick bcopy(*addrp, *naddrp, 130051898Smckusick hp->h_length); 130151898Smckusick addrp++; 130251898Smckusick naddrp++; 130351898Smckusick } 130466163Spendry *naddrp = (char *)NULL; 130553150Smckusick if (debug) 130653150Smckusick fprintf(stderr, "got host %s\n", hp->h_name); 130751898Smckusick return (0); 130851898Smckusick } 130951898Smckusick 131051898Smckusick /* 131151898Smckusick * Free up an exports list component 131251898Smckusick */ 131351898Smckusick void 131451898Smckusick free_exp(ep) 131566163Spendry struct exportlist *ep; 131651898Smckusick { 131751898Smckusick 131851898Smckusick if (ep->ex_defdir) { 131951898Smckusick free_host(ep->ex_defdir->dp_hosts); 132051898Smckusick free((caddr_t)ep->ex_defdir); 132151898Smckusick } 132251898Smckusick if (ep->ex_fsdir) 132351898Smckusick free(ep->ex_fsdir); 132451898Smckusick free_dir(ep->ex_dirl); 132551898Smckusick free((caddr_t)ep); 132651898Smckusick } 132751898Smckusick 132851898Smckusick /* 132951898Smckusick * Free hosts. 133051898Smckusick */ 133151898Smckusick void 133251898Smckusick free_host(hp) 133366163Spendry struct hostlist *hp; 133451898Smckusick { 133566163Spendry struct hostlist *hp2; 133651898Smckusick 133751898Smckusick while (hp) { 133851898Smckusick hp2 = hp; 133951898Smckusick hp = hp->ht_next; 134051898Smckusick free((caddr_t)hp2); 134151898Smckusick } 134251898Smckusick } 134351898Smckusick 134451898Smckusick struct hostlist * 134551898Smckusick get_ht() 134651898Smckusick { 134766163Spendry struct hostlist *hp; 134851898Smckusick 134951898Smckusick hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 135066163Spendry if (hp == (struct hostlist *)NULL) 135151898Smckusick out_of_mem(); 135266163Spendry hp->ht_next = (struct hostlist *)NULL; 135351898Smckusick return (hp); 135451898Smckusick } 135551898Smckusick 135651898Smckusick #ifdef ISO 135751898Smckusick /* 135851898Smckusick * Translate an iso address. 135951898Smckusick */ 136051898Smckusick get_isoaddr(cp, grp) 136151898Smckusick char *cp; 136251898Smckusick struct grouplist *grp; 136351898Smckusick { 136451898Smckusick struct iso_addr *isop; 136551898Smckusick struct sockaddr_iso *isoaddr; 136651898Smckusick 136751898Smckusick if (grp->gr_type != GT_NULL) 136851898Smckusick return (1); 136951898Smckusick if ((isop = iso_addr(cp)) == NULL) { 137051898Smckusick syslog(LOG_ERR, 137151898Smckusick "iso_addr failed, ignored"); 137251898Smckusick return (1); 137351898Smckusick } 137451898Smckusick isoaddr = (struct sockaddr_iso *) 137551898Smckusick malloc(sizeof (struct sockaddr_iso)); 137666163Spendry if (isoaddr == (struct sockaddr_iso *)NULL) 137751898Smckusick out_of_mem(); 137851898Smckusick bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 137951898Smckusick bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 138051898Smckusick sizeof (struct iso_addr)); 138151898Smckusick isoaddr->siso_len = sizeof (struct sockaddr_iso); 138251898Smckusick isoaddr->siso_family = AF_ISO; 138351898Smckusick grp->gr_type = GT_ISO; 138451898Smckusick grp->gr_ptr.gt_isoaddr = isoaddr; 138551898Smckusick return (0); 138651898Smckusick } 138751898Smckusick #endif /* ISO */ 138851898Smckusick 138951898Smckusick /* 139051898Smckusick * Out of memory, fatal 139151898Smckusick */ 139251898Smckusick void 139351898Smckusick out_of_mem() 139451898Smckusick { 139551898Smckusick 139651898Smckusick syslog(LOG_ERR, "Out of memory"); 139751667Smckusick exit(2); 139851667Smckusick } 139951667Smckusick 140051898Smckusick /* 140151898Smckusick * Do the mount syscall with the update flag to push the export info into 140251898Smckusick * the kernel. 140351898Smckusick */ 140466163Spendry int 140551898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 140651667Smckusick struct exportlist *ep; 140751667Smckusick struct grouplist *grp; 140851898Smckusick int exflags; 140951667Smckusick struct ucred *anoncrp; 141051898Smckusick char *dirp; 141151898Smckusick int dirplen; 141251898Smckusick struct statfs *fsb; 141351667Smckusick { 141466163Spendry char *cp = (char *)NULL; 141566163Spendry u_long **addrp; 141651898Smckusick int done; 141766163Spendry char savedc = '\0'; 141851898Smckusick struct sockaddr_in sin, imask; 141965713Shibler union { 142065713Shibler struct ufs_args ua; 142165713Shibler struct iso_args ia; 142265713Shibler struct mfs_args ma; 142365713Shibler } args; 142451898Smckusick u_long net; 142551667Smckusick 142665713Shibler args.ua.fspec = 0; 142765713Shibler args.ua.export.ex_flags = exflags; 142865713Shibler args.ua.export.ex_anon = *anoncrp; 142955878Smckusick bzero((char *)&sin, sizeof(sin)); 143055878Smckusick bzero((char *)&imask, sizeof(imask)); 143151667Smckusick sin.sin_family = AF_INET; 143251667Smckusick sin.sin_len = sizeof(sin); 143351898Smckusick imask.sin_family = AF_INET; 143451898Smckusick imask.sin_len = sizeof(sin); 143551898Smckusick if (grp->gr_type == GT_HOST) 143651667Smckusick addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 143751898Smckusick else 143866163Spendry addrp = (u_long **)NULL; 143951667Smckusick done = FALSE; 144051898Smckusick while (!done) { 144151898Smckusick switch (grp->gr_type) { 144251898Smckusick case GT_HOST: 144364903Smckusick if (addrp) { 144451712Smckusick sin.sin_addr.s_addr = **addrp; 144565713Shibler args.ua.export.ex_addrlen = sizeof(sin); 144664903Smckusick } else 144765713Shibler args.ua.export.ex_addrlen = 0; 144865713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 144965713Shibler args.ua.export.ex_masklen = 0; 145051898Smckusick break; 145151898Smckusick case GT_NET: 145251898Smckusick if (grp->gr_ptr.gt_net.nt_mask) 145351898Smckusick imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 145451898Smckusick else { 145551898Smckusick net = ntohl(grp->gr_ptr.gt_net.nt_net); 145651898Smckusick if (IN_CLASSA(net)) 145751898Smckusick imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 145851898Smckusick else if (IN_CLASSB(net)) 145951898Smckusick imask.sin_addr.s_addr = 146051898Smckusick inet_addr("255.255.0.0"); 146151898Smckusick else 146251898Smckusick imask.sin_addr.s_addr = 146351898Smckusick inet_addr("255.255.255.0"); 146451898Smckusick grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 146551898Smckusick } 146651898Smckusick sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 146765713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 146865713Shibler args.ua.export.ex_addrlen = sizeof (sin); 146965713Shibler args.ua.export.ex_mask = (struct sockaddr *)&imask; 147065713Shibler args.ua.export.ex_masklen = sizeof (imask); 147151898Smckusick break; 147251667Smckusick #ifdef ISO 147351898Smckusick case GT_ISO: 147465713Shibler args.ua.export.ex_addr = 147565713Shibler (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 147665713Shibler args.ua.export.ex_addrlen = 147765713Shibler sizeof(struct sockaddr_iso); 147865713Shibler args.ua.export.ex_masklen = 0; 147951898Smckusick break; 148051667Smckusick #endif /* ISO */ 148151898Smckusick default: 148251667Smckusick syslog(LOG_ERR, "Bad grouptype"); 148351898Smckusick if (cp) 148451898Smckusick *cp = savedc; 148551898Smckusick return (1); 148651898Smckusick }; 148752109Smckusick 148852109Smckusick /* 148952109Smckusick * XXX: 149052109Smckusick * Maybe I should just use the fsb->f_mntonname path instead 149152109Smckusick * of looping back up the dirp to the mount point?? 149252109Smckusick * Also, needs to know how to export all types of local 149352109Smckusick * exportable file systems and not just MOUNT_UFS. 149452109Smckusick */ 149552109Smckusick while (mount(fsb->f_type, dirp, 149652109Smckusick fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 149751898Smckusick if (cp) 149851898Smckusick *cp-- = savedc; 149951898Smckusick else 150051898Smckusick cp = dirp + dirplen - 1; 150151667Smckusick if (errno == EPERM) { 150251667Smckusick syslog(LOG_ERR, 150351898Smckusick "Can't change attributes for %s.\n", dirp); 150451898Smckusick return (1); 150551667Smckusick } 150651898Smckusick if (opt_flags & OP_ALLDIRS) { 150751898Smckusick syslog(LOG_ERR, "Not root dir"); 150851898Smckusick return (1); 150951898Smckusick } 151051667Smckusick /* back up over the last component */ 151151898Smckusick while (*cp == '/' && cp > dirp) 151251667Smckusick cp--; 151351898Smckusick while (*(cp - 1) != '/' && cp > dirp) 151451667Smckusick cp--; 151551898Smckusick if (cp == dirp) { 151651898Smckusick if (debug) 151751667Smckusick fprintf(stderr,"mnt unsucc\n"); 151851898Smckusick syslog(LOG_ERR, "Can't export %s", dirp); 151951898Smckusick return (1); 152051667Smckusick } 152151667Smckusick savedc = *cp; 152251667Smckusick *cp = '\0'; 152351667Smckusick } 152451898Smckusick if (addrp) { 152551667Smckusick ++addrp; 152666163Spendry if (*addrp == (u_long *)NULL) 152751667Smckusick done = TRUE; 152851898Smckusick } else 152951898Smckusick done = TRUE; 153051898Smckusick } 153151898Smckusick if (cp) 153251898Smckusick *cp = savedc; 153351898Smckusick return (0); 153451898Smckusick } 153551898Smckusick 153651898Smckusick /* 153751898Smckusick * Translate a net address. 153851898Smckusick */ 153966163Spendry int 154051898Smckusick get_net(cp, net, maskflg) 154151898Smckusick char *cp; 154251898Smckusick struct netmsk *net; 154351898Smckusick int maskflg; 154451898Smckusick { 154566163Spendry struct netent *np; 154666163Spendry long netaddr; 154751898Smckusick struct in_addr inetaddr, inetaddr2; 154851898Smckusick char *name; 154951898Smckusick 155051898Smckusick if (np = getnetbyname(cp)) 155151898Smckusick inetaddr = inet_makeaddr(np->n_net, 0); 155251898Smckusick else if (isdigit(*cp)) { 155351898Smckusick if ((netaddr = inet_network(cp)) == -1) 155451898Smckusick return (1); 155551898Smckusick inetaddr = inet_makeaddr(netaddr, 0); 155651898Smckusick /* 155751898Smckusick * Due to arbritrary subnet masks, you don't know how many 155851898Smckusick * bits to shift the address to make it into a network, 155951898Smckusick * however you do know how to make a network address into 156051898Smckusick * a host with host == 0 and then compare them. 156151898Smckusick * (What a pest) 156251898Smckusick */ 156351898Smckusick if (!maskflg) { 156451898Smckusick setnetent(0); 156551898Smckusick while (np = getnetent()) { 156651898Smckusick inetaddr2 = inet_makeaddr(np->n_net, 0); 156751898Smckusick if (inetaddr2.s_addr == inetaddr.s_addr) 156851898Smckusick break; 156951898Smckusick } 157051898Smckusick endnetent(); 157151667Smckusick } 157251898Smckusick } else 157351898Smckusick return (1); 157451898Smckusick if (maskflg) 157551898Smckusick net->nt_mask = inetaddr.s_addr; 157651898Smckusick else { 157751898Smckusick if (np) 157851898Smckusick name = np->n_name; 157951898Smckusick else 158051898Smckusick name = inet_ntoa(inetaddr); 158151898Smckusick net->nt_name = (char *)malloc(strlen(name) + 1); 158266163Spendry if (net->nt_name == (char *)NULL) 158351898Smckusick out_of_mem(); 158451898Smckusick strcpy(net->nt_name, name); 158551898Smckusick net->nt_net = inetaddr.s_addr; 158638460Smckusick } 158751898Smckusick return (0); 158838460Smckusick } 158938460Smckusick 159038460Smckusick /* 159138460Smckusick * Parse out the next white space separated field 159238460Smckusick */ 159351667Smckusick void 159438460Smckusick nextfield(cp, endcp) 159538460Smckusick char **cp; 159638460Smckusick char **endcp; 159738460Smckusick { 159866163Spendry char *p; 159938460Smckusick 160038460Smckusick p = *cp; 160138460Smckusick while (*p == ' ' || *p == '\t') 160238460Smckusick p++; 160351898Smckusick if (*p == '\n' || *p == '\0') 160438460Smckusick *cp = *endcp = p; 160551898Smckusick else { 160651898Smckusick *cp = p++; 160751898Smckusick while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 160851898Smckusick p++; 160951898Smckusick *endcp = p; 161038460Smckusick } 161138460Smckusick } 161239681Smckusick 161339681Smckusick /* 161451898Smckusick * Get an exports file line. Skip over blank lines and handle line 161551898Smckusick * continuations. 161639681Smckusick */ 161766163Spendry int 161851898Smckusick get_line() 161939681Smckusick { 162066163Spendry char *p, *cp; 162166163Spendry int len; 162251898Smckusick int totlen, cont_line; 162339681Smckusick 162451898Smckusick /* 162551898Smckusick * Loop around ignoring blank lines and getting all continuation lines. 162651898Smckusick */ 162751898Smckusick p = line; 162851898Smckusick totlen = 0; 162951898Smckusick do { 163051898Smckusick if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 163151898Smckusick return (0); 163251898Smckusick len = strlen(p); 163351898Smckusick cp = p + len - 1; 163451898Smckusick cont_line = 0; 163551898Smckusick while (cp >= p && 163651898Smckusick (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 163751898Smckusick if (*cp == '\\') 163851898Smckusick cont_line = 1; 163951898Smckusick cp--; 164051898Smckusick len--; 164151898Smckusick } 164251898Smckusick *++cp = '\0'; 164351898Smckusick if (len > 0) { 164451898Smckusick totlen += len; 164551898Smckusick if (totlen >= LINESIZ) { 164651898Smckusick syslog(LOG_ERR, "Exports line too long"); 164751898Smckusick exit(2); 164851898Smckusick } 164951898Smckusick p = cp; 165051898Smckusick } 165151898Smckusick } while (totlen == 0 || cont_line); 165251898Smckusick return (1); 165344015Smckusick } 165444015Smckusick 165551667Smckusick /* 165651667Smckusick * Parse a description of a credential. 165751667Smckusick */ 165866163Spendry void 165951667Smckusick parsecred(namelist, cr) 166051667Smckusick char *namelist; 166166163Spendry struct ucred *cr; 166251667Smckusick { 166366163Spendry char *name; 166466163Spendry int cnt; 166551667Smckusick char *names; 166651667Smckusick struct passwd *pw; 166751667Smckusick struct group *gr; 166851667Smckusick int ngroups, groups[NGROUPS + 1]; 166951667Smckusick 167051667Smckusick /* 167151667Smckusick * Set up the unpriviledged user. 167251667Smckusick */ 167351667Smckusick cr->cr_ref = 1; 167451667Smckusick cr->cr_uid = -2; 167551667Smckusick cr->cr_groups[0] = -2; 167651667Smckusick cr->cr_ngroups = 1; 167751667Smckusick /* 167851667Smckusick * Get the user's password table entry. 167951667Smckusick */ 168051667Smckusick names = strsep(&namelist, " \t\n"); 168151667Smckusick name = strsep(&names, ":"); 168251667Smckusick if (isdigit(*name) || *name == '-') 168351667Smckusick pw = getpwuid(atoi(name)); 168451667Smckusick else 168551667Smckusick pw = getpwnam(name); 168651667Smckusick /* 168751667Smckusick * Credentials specified as those of a user. 168851667Smckusick */ 168951667Smckusick if (names == NULL) { 169051667Smckusick if (pw == NULL) { 169166163Spendry syslog(LOG_ERR, "Unknown user: %s", name); 169251667Smckusick return; 169351667Smckusick } 169451667Smckusick cr->cr_uid = pw->pw_uid; 169551667Smckusick ngroups = NGROUPS + 1; 169651667Smckusick if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 169766163Spendry syslog(LOG_ERR, "Too many groups"); 169851667Smckusick /* 169951667Smckusick * Convert from int's to gid_t's and compress out duplicate 170051667Smckusick */ 170151667Smckusick cr->cr_ngroups = ngroups - 1; 170251667Smckusick cr->cr_groups[0] = groups[0]; 170351667Smckusick for (cnt = 2; cnt < ngroups; cnt++) 170451667Smckusick cr->cr_groups[cnt - 1] = groups[cnt]; 170551667Smckusick return; 170651667Smckusick } 170751667Smckusick /* 170851667Smckusick * Explicit credential specified as a colon separated list: 170951667Smckusick * uid:gid:gid:... 171051667Smckusick */ 171151667Smckusick if (pw != NULL) 171251667Smckusick cr->cr_uid = pw->pw_uid; 171351667Smckusick else if (isdigit(*name) || *name == '-') 171451667Smckusick cr->cr_uid = atoi(name); 171551667Smckusick else { 171666163Spendry syslog(LOG_ERR, "Unknown user: %s", name); 171751667Smckusick return; 171851667Smckusick } 171951667Smckusick cr->cr_ngroups = 0; 172051667Smckusick while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 172151667Smckusick name = strsep(&names, ":"); 172251667Smckusick if (isdigit(*name) || *name == '-') { 172351667Smckusick cr->cr_groups[cr->cr_ngroups++] = atoi(name); 172451667Smckusick } else { 172551667Smckusick if ((gr = getgrnam(name)) == NULL) { 172666163Spendry syslog(LOG_ERR, "Unknown group: %s", name); 172751667Smckusick continue; 172851667Smckusick } 172951667Smckusick cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 173051667Smckusick } 173151667Smckusick } 173251667Smckusick if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 173366163Spendry syslog(LOG_ERR, "Too many groups"); 173451667Smckusick } 173551667Smckusick 173644015Smckusick #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 173744015Smckusick /* 173844015Smckusick * Routines that maintain the remote mounttab 173944015Smckusick */ 174051667Smckusick void 174151667Smckusick get_mountlist() 174244015Smckusick { 174366163Spendry struct mountlist *mlp, **mlpp; 174466163Spendry char *eos, *dirp; 174544015Smckusick int len; 174644015Smckusick char str[STRSIZ]; 174744015Smckusick FILE *mlfile; 174844015Smckusick 174951712Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 175051667Smckusick syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 175144015Smckusick return; 175244015Smckusick } 175344015Smckusick mlpp = &mlhead; 175444015Smckusick while (fgets(str, STRSIZ, mlfile) != NULL) { 175544015Smckusick if ((dirp = index(str, '\t')) == NULL && 175644015Smckusick (dirp = index(str, ' ')) == NULL) 175744015Smckusick continue; 175844015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 175944015Smckusick len = dirp-str; 176044015Smckusick if (len > RPCMNT_NAMELEN) 176144015Smckusick len = RPCMNT_NAMELEN; 176244015Smckusick bcopy(str, mlp->ml_host, len); 176344015Smckusick mlp->ml_host[len] = '\0'; 176444015Smckusick while (*dirp == '\t' || *dirp == ' ') 176544015Smckusick dirp++; 176644015Smckusick if ((eos = index(dirp, '\t')) == NULL && 176744015Smckusick (eos = index(dirp, ' ')) == NULL && 176844015Smckusick (eos = index(dirp, '\n')) == NULL) 176944015Smckusick len = strlen(dirp); 177044015Smckusick else 177144015Smckusick len = eos-dirp; 177244015Smckusick if (len > RPCMNT_PATHLEN) 177344015Smckusick len = RPCMNT_PATHLEN; 177444015Smckusick bcopy(dirp, mlp->ml_dirp, len); 177544015Smckusick mlp->ml_dirp[len] = '\0'; 177666163Spendry mlp->ml_next = (struct mountlist *)NULL; 177744015Smckusick *mlpp = mlp; 177844015Smckusick mlpp = &mlp->ml_next; 177944015Smckusick } 178044015Smckusick fclose(mlfile); 178144015Smckusick } 178244015Smckusick 178351667Smckusick void 178451667Smckusick del_mlist(hostp, dirp) 178566163Spendry char *hostp, *dirp; 178644015Smckusick { 178766163Spendry struct mountlist *mlp, **mlpp; 178851712Smckusick struct mountlist *mlp2; 178944015Smckusick FILE *mlfile; 179044015Smckusick int fnd = 0; 179144015Smckusick 179244015Smckusick mlpp = &mlhead; 179344015Smckusick mlp = mlhead; 179444015Smckusick while (mlp) { 179544015Smckusick if (!strcmp(mlp->ml_host, hostp) && 179644015Smckusick (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 179744015Smckusick fnd = 1; 179851712Smckusick mlp2 = mlp; 179951712Smckusick *mlpp = mlp = mlp->ml_next; 180051712Smckusick free((caddr_t)mlp2); 180151712Smckusick } else { 180251712Smckusick mlpp = &mlp->ml_next; 180351712Smckusick mlp = mlp->ml_next; 180439681Smckusick } 180539681Smckusick } 180644015Smckusick if (fnd) { 180744015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 180851898Smckusick syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 180944015Smckusick return; 181044015Smckusick } 181144015Smckusick mlp = mlhead; 181244015Smckusick while (mlp) { 181344015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 181444015Smckusick mlp = mlp->ml_next; 181544015Smckusick } 181644015Smckusick fclose(mlfile); 181744015Smckusick } 181839681Smckusick } 181944015Smckusick 182051667Smckusick void 182151667Smckusick add_mlist(hostp, dirp) 182266163Spendry char *hostp, *dirp; 182344015Smckusick { 182466163Spendry struct mountlist *mlp, **mlpp; 182544015Smckusick FILE *mlfile; 182644015Smckusick 182744015Smckusick mlpp = &mlhead; 182844015Smckusick mlp = mlhead; 182944015Smckusick while (mlp) { 183044015Smckusick if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 183144015Smckusick return; 183244015Smckusick mlpp = &mlp->ml_next; 183344015Smckusick mlp = mlp->ml_next; 183444015Smckusick } 183544015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 183644015Smckusick strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 183744015Smckusick mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 183844015Smckusick strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 183944015Smckusick mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 184066163Spendry mlp->ml_next = (struct mountlist *)NULL; 184144015Smckusick *mlpp = mlp; 184244015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 184351898Smckusick syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 184444015Smckusick return; 184544015Smckusick } 184644015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 184744015Smckusick fclose(mlfile); 184844015Smckusick } 184944015Smckusick 185044015Smckusick /* 185144015Smckusick * This function is called via. SIGTERM when the system is going down. 185244015Smckusick * It sends a broadcast RPCMNT_UMNTALL. 185344015Smckusick */ 185446709Sbostic void 185544015Smckusick send_umntall() 185644015Smckusick { 185744015Smckusick (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 185844015Smckusick xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 185951667Smckusick exit(0); 186044015Smckusick } 186144015Smckusick 186266163Spendry int 186344015Smckusick umntall_each(resultsp, raddr) 186444015Smckusick caddr_t resultsp; 186544015Smckusick struct sockaddr_in *raddr; 186644015Smckusick { 186744015Smckusick return (1); 186844015Smckusick } 186944015Smckusick 187044015Smckusick /* 187151667Smckusick * Free up a group list. 187251667Smckusick */ 187351667Smckusick void 187451667Smckusick free_grp(grp) 187566163Spendry struct grouplist *grp; 187651667Smckusick { 187766163Spendry char **addrp; 187851667Smckusick 187951898Smckusick if (grp->gr_type == GT_HOST) { 188051712Smckusick if (grp->gr_ptr.gt_hostent->h_name) { 188151712Smckusick addrp = grp->gr_ptr.gt_hostent->h_addr_list; 188251712Smckusick while (addrp && *addrp) 188351712Smckusick free(*addrp++); 188451712Smckusick free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 188551712Smckusick free(grp->gr_ptr.gt_hostent->h_name); 188651712Smckusick } 188751667Smckusick free((caddr_t)grp->gr_ptr.gt_hostent); 188851898Smckusick } else if (grp->gr_type == GT_NET) { 188951898Smckusick if (grp->gr_ptr.gt_net.nt_name) 189051898Smckusick free(grp->gr_ptr.gt_net.nt_name); 189151667Smckusick } 189251667Smckusick #ifdef ISO 189351898Smckusick else if (grp->gr_type == GT_ISO) 189451667Smckusick free((caddr_t)grp->gr_ptr.gt_isoaddr); 189551667Smckusick #endif 189651667Smckusick free((caddr_t)grp); 189751667Smckusick } 189851667Smckusick 189951711Smckusick #ifdef DEBUG 190051711Smckusick void 190151711Smckusick SYSLOG(int pri, const char *fmt, ...) 190251711Smckusick { 190351711Smckusick va_list ap; 190451711Smckusick 190551711Smckusick va_start(ap, fmt); 190651711Smckusick vfprintf(stderr, fmt, ap); 190751711Smckusick va_end(ap); 190851711Smckusick } 190951711Smckusick #endif /* DEBUG */ 191051898Smckusick 191151898Smckusick /* 191251898Smckusick * Check options for consistency. 191351898Smckusick */ 191466163Spendry int 191551898Smckusick check_options(dp) 191651898Smckusick struct dirlist *dp; 191751898Smckusick { 191851898Smckusick 191966163Spendry if (dp == (struct dirlist *)NULL) 192051898Smckusick return (1); 192151898Smckusick if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 192251898Smckusick (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 192351898Smckusick (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 192451898Smckusick syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 192551898Smckusick return (1); 192651898Smckusick } 192751898Smckusick if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 192851898Smckusick syslog(LOG_ERR, "-mask requires -net"); 192951898Smckusick return (1); 193051898Smckusick } 193151898Smckusick if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 193251898Smckusick syslog(LOG_ERR, "-net and -iso mutually exclusive"); 193351898Smckusick return (1); 193451898Smckusick } 193551898Smckusick if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 193651898Smckusick syslog(LOG_ERR, "-alldir has multiple directories"); 193751898Smckusick return (1); 193851898Smckusick } 193951898Smckusick return (0); 194051898Smckusick } 194165940Sbostic 194265940Sbostic /* 194365940Sbostic * Check an absolute directory path for any symbolic links. Return true 194465940Sbostic * if no symbolic links are found. 194565940Sbostic */ 194665940Sbostic int 194765940Sbostic check_dirpath(dirp) 194866163Spendry char *dirp; 194965940Sbostic { 195066163Spendry char *cp; 195165940Sbostic int ret = 1; 195265940Sbostic struct stat sb; 195365940Sbostic 195465940Sbostic cp = dirp + 1; 195565940Sbostic while (*cp && ret) { 195665940Sbostic if (*cp == '/') { 195765940Sbostic *cp = '\0'; 195867383Smkm if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 195965940Sbostic ret = 0; 196065940Sbostic *cp = '/'; 196165940Sbostic } 196265940Sbostic cp++; 196365940Sbostic } 196467383Smkm if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 196565940Sbostic ret = 0; 196665940Sbostic return (ret); 196765940Sbostic } 1968