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*67383Smkm static char sccsid[] = "@(#)mountd.c 8.9 (Berkeley) 06/14/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 }; 17944015Smckusick int root_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': 21644015Smckusick root_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 authunix_parms *ucr; 28138460Smckusick struct stat stb; 28251898Smckusick struct statfs fsb; 28338460Smckusick struct hostent *hp; 28439681Smckusick u_long saddr; 28551667Smckusick char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; 28651898Smckusick int bad = ENOENT, omask, defset; 28739681Smckusick uid_t uid = -2; 28838460Smckusick 28938460Smckusick /* Get authorization */ 29038460Smckusick switch (rqstp->rq_cred.oa_flavor) { 29138460Smckusick case AUTH_UNIX: 29238460Smckusick ucr = (struct authunix_parms *)rqstp->rq_clntcred; 29339681Smckusick uid = ucr->aup_uid; 29439681Smckusick break; 29538460Smckusick case AUTH_NULL: 29638460Smckusick default: 29739681Smckusick break; 29838460Smckusick } 29938460Smckusick 30039681Smckusick saddr = transp->xp_raddr.sin_addr.s_addr; 30166163Spendry hp = (struct hostent *)NULL; 30238460Smckusick switch (rqstp->rq_proc) { 30339681Smckusick case NULLPROC: 30466163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 30539681Smckusick syslog(LOG_ERR, "Can't send reply"); 30639681Smckusick return; 30738460Smckusick case RPCMNT_MOUNT: 30851667Smckusick if ((uid != 0 && root_only) || uid == -2) { 30939681Smckusick svcerr_weakauth(transp); 31039681Smckusick return; 31139681Smckusick } 31251667Smckusick if (!svc_getargs(transp, xdr_dir, rpcpath)) { 31338460Smckusick svcerr_decode(transp); 31438460Smckusick return; 31538460Smckusick } 31638460Smckusick 31751667Smckusick /* 31851667Smckusick * Get the real pathname and make sure it is a directory 31951667Smckusick * that exists. 32051667Smckusick */ 32151898Smckusick if (realpath(rpcpath, dirpath) == 0 || 32251898Smckusick stat(dirpath, &stb) < 0 || 323*67383Smkm (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) || 32451898Smckusick statfs(dirpath, &fsb) < 0) { 32551667Smckusick chdir("/"); /* Just in case realpath doesn't */ 32651667Smckusick if (debug) 32751898Smckusick fprintf(stderr, "stat failed on %s\n", dirpath); 32838460Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 32938460Smckusick syslog(LOG_ERR, "Can't send reply"); 33038460Smckusick return; 33138460Smckusick } 33238460Smckusick 33338460Smckusick /* Check in the exports list */ 33438460Smckusick omask = sigblock(sigmask(SIGHUP)); 33551898Smckusick ep = ex_search(&fsb.f_fsid); 33651898Smckusick defset = 0; 33751898Smckusick if (ep && (chk_host(ep->ex_defdir, saddr, &defset) || 33851898Smckusick ((dp = dirp_search(ep->ex_dirl, dirpath)) && 33951898Smckusick chk_host(dp, saddr, &defset)) || 34051898Smckusick (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 34151898Smckusick scan_tree(ep->ex_dirl, saddr) == 0))) { 34251667Smckusick /* Get the file handle */ 34351667Smckusick bzero((caddr_t)&nfh, sizeof(nfh)); 34451667Smckusick if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { 34551667Smckusick bad = errno; 34651898Smckusick syslog(LOG_ERR, "Can't get fh for %s", dirpath); 34751667Smckusick if (!svc_sendreply(transp, xdr_long, 34851667Smckusick (caddr_t)&bad)) 34951667Smckusick syslog(LOG_ERR, "Can't send reply"); 35051667Smckusick sigsetmask(omask); 35151667Smckusick return; 35251667Smckusick } 35351667Smckusick if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) 35438460Smckusick syslog(LOG_ERR, "Can't send reply"); 35551667Smckusick if (hp == NULL) 35651667Smckusick hp = gethostbyaddr((caddr_t)&saddr, 35751667Smckusick sizeof(saddr), AF_INET); 35851667Smckusick if (hp) 35951667Smckusick add_mlist(hp->h_name, dirpath); 36051667Smckusick else 36151667Smckusick add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 36251667Smckusick dirpath); 36351667Smckusick if (debug) 36451667Smckusick fprintf(stderr,"Mount successfull.\n"); 36551898Smckusick } else { 36651898Smckusick bad = EACCES; 36751898Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 36851898Smckusick syslog(LOG_ERR, "Can't send reply"); 36938460Smckusick } 37051667Smckusick sigsetmask(omask); 37138460Smckusick return; 37238460Smckusick case RPCMNT_DUMP: 37366163Spendry if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) 37438460Smckusick syslog(LOG_ERR, "Can't send reply"); 37538460Smckusick return; 37638460Smckusick case RPCMNT_UMOUNT: 37751667Smckusick if ((uid != 0 && root_only) || uid == -2) { 37839681Smckusick svcerr_weakauth(transp); 37939681Smckusick return; 38039681Smckusick } 38138460Smckusick if (!svc_getargs(transp, xdr_dir, dirpath)) { 38238460Smckusick svcerr_decode(transp); 38338460Smckusick return; 38438460Smckusick } 38566163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 38638460Smckusick syslog(LOG_ERR, "Can't send reply"); 38744015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 38844015Smckusick if (hp) 38944015Smckusick del_mlist(hp->h_name, dirpath); 39051667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 39138460Smckusick return; 39238460Smckusick case RPCMNT_UMNTALL: 39351667Smckusick if ((uid != 0 && root_only) || uid == -2) { 39439681Smckusick svcerr_weakauth(transp); 39539681Smckusick return; 39639681Smckusick } 39766163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 39838460Smckusick syslog(LOG_ERR, "Can't send reply"); 39944015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 40044015Smckusick if (hp) 40166163Spendry del_mlist(hp->h_name, (char *)NULL); 40266163Spendry del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL); 40338460Smckusick return; 40438460Smckusick case RPCMNT_EXPORT: 40566163Spendry if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) 40638460Smckusick syslog(LOG_ERR, "Can't send reply"); 40738460Smckusick return; 40838460Smckusick default: 40938460Smckusick svcerr_noproc(transp); 41038460Smckusick return; 41138460Smckusick } 41238460Smckusick } 41338460Smckusick 41438460Smckusick /* 41538460Smckusick * Xdr conversion for a dirpath string 41638460Smckusick */ 41766163Spendry int 41838460Smckusick xdr_dir(xdrsp, dirp) 41938460Smckusick XDR *xdrsp; 42038460Smckusick char *dirp; 42138460Smckusick { 42238460Smckusick return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 42338460Smckusick } 42438460Smckusick 42538460Smckusick /* 42638460Smckusick * Xdr routine to generate fhstatus 42738460Smckusick */ 42866163Spendry int 42938460Smckusick xdr_fhs(xdrsp, nfh) 43038460Smckusick XDR *xdrsp; 43138460Smckusick nfsv2fh_t *nfh; 43238460Smckusick { 43338460Smckusick int ok = 0; 43438460Smckusick 43538460Smckusick if (!xdr_long(xdrsp, &ok)) 43638460Smckusick return (0); 43738460Smckusick return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); 43838460Smckusick } 43938460Smckusick 44066163Spendry int 44138460Smckusick xdr_mlist(xdrsp, cp) 44238460Smckusick XDR *xdrsp; 44338460Smckusick caddr_t cp; 44438460Smckusick { 44566163Spendry struct mountlist *mlp; 44638460Smckusick int true = 1; 44738460Smckusick int false = 0; 44838460Smckusick char *strp; 44938460Smckusick 45044015Smckusick mlp = mlhead; 45144015Smckusick while (mlp) { 45244015Smckusick if (!xdr_bool(xdrsp, &true)) 45344015Smckusick return (0); 45444015Smckusick strp = &mlp->ml_host[0]; 45544015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 45644015Smckusick return (0); 45744015Smckusick strp = &mlp->ml_dirp[0]; 45844015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 45944015Smckusick return (0); 46044015Smckusick mlp = mlp->ml_next; 46138460Smckusick } 46238460Smckusick if (!xdr_bool(xdrsp, &false)) 46338460Smckusick return (0); 46438460Smckusick return (1); 46538460Smckusick } 46638460Smckusick 46738460Smckusick /* 46838460Smckusick * Xdr conversion for export list 46938460Smckusick */ 47066163Spendry int 47138460Smckusick xdr_explist(xdrsp, cp) 47238460Smckusick XDR *xdrsp; 47338460Smckusick caddr_t cp; 47438460Smckusick { 47566163Spendry struct exportlist *ep; 47638460Smckusick int false = 0; 47764903Smckusick int omask, putdef; 47838460Smckusick 47938460Smckusick omask = sigblock(sigmask(SIGHUP)); 48051898Smckusick ep = exphead; 48151898Smckusick while (ep) { 48264903Smckusick putdef = 0; 48364903Smckusick if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 48438460Smckusick goto errout; 48564903Smckusick if (ep->ex_defdir && putdef == 0 && 48666163Spendry put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 48764903Smckusick &putdef)) 48864903Smckusick goto errout; 48938460Smckusick ep = ep->ex_next; 49038460Smckusick } 49138460Smckusick sigsetmask(omask); 49238460Smckusick if (!xdr_bool(xdrsp, &false)) 49338460Smckusick return (0); 49438460Smckusick return (1); 49538460Smckusick errout: 49638460Smckusick sigsetmask(omask); 49738460Smckusick return (0); 49838460Smckusick } 49938460Smckusick 50051898Smckusick /* 50151898Smckusick * Called from xdr_explist() to traverse the tree and export the 50251898Smckusick * directory paths. 50351898Smckusick */ 50466163Spendry int 50564903Smckusick put_exlist(dp, xdrsp, adp, putdefp) 50666163Spendry struct dirlist *dp; 50751898Smckusick XDR *xdrsp; 50851898Smckusick struct dirlist *adp; 50964903Smckusick int *putdefp; 51051898Smckusick { 51166163Spendry struct grouplist *grp; 51266163Spendry struct hostlist *hp; 51351898Smckusick int true = 1; 51451898Smckusick int false = 0; 51551898Smckusick int gotalldir = 0; 51651898Smckusick char *strp; 51751898Smckusick 51851898Smckusick if (dp) { 51964903Smckusick if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 52051898Smckusick return (1); 52151898Smckusick if (!xdr_bool(xdrsp, &true)) 52251898Smckusick return (1); 52351898Smckusick strp = dp->dp_dirp; 52451898Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 52551898Smckusick return (1); 52664903Smckusick if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 52751898Smckusick gotalldir = 1; 52864903Smckusick *putdefp = 1; 52964903Smckusick } 53051898Smckusick if ((dp->dp_flag & DP_DEFSET) == 0 && 53151898Smckusick (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 53251898Smckusick hp = dp->dp_hosts; 53351898Smckusick while (hp) { 53451898Smckusick grp = hp->ht_grp; 53551898Smckusick if (grp->gr_type == GT_HOST) { 53651898Smckusick if (!xdr_bool(xdrsp, &true)) 53751898Smckusick return (1); 53851898Smckusick strp = grp->gr_ptr.gt_hostent->h_name; 53951898Smckusick if (!xdr_string(xdrsp, &strp, 54051898Smckusick RPCMNT_NAMELEN)) 54151898Smckusick return (1); 54251898Smckusick } else if (grp->gr_type == GT_NET) { 54351898Smckusick if (!xdr_bool(xdrsp, &true)) 54451898Smckusick return (1); 54551898Smckusick strp = grp->gr_ptr.gt_net.nt_name; 54651898Smckusick if (!xdr_string(xdrsp, &strp, 54751898Smckusick RPCMNT_NAMELEN)) 54851898Smckusick return (1); 54951898Smckusick } 55051898Smckusick hp = hp->ht_next; 55166163Spendry if (gotalldir && hp == (struct hostlist *)NULL) { 55251898Smckusick hp = adp->dp_hosts; 55351898Smckusick gotalldir = 0; 55451898Smckusick } 55551898Smckusick } 55651898Smckusick } 55751898Smckusick if (!xdr_bool(xdrsp, &false)) 55851898Smckusick return (1); 55964903Smckusick if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 56051898Smckusick return (1); 56151898Smckusick } 56251898Smckusick return (0); 56351898Smckusick } 56451898Smckusick 56538460Smckusick #define LINESIZ 10240 56638460Smckusick char line[LINESIZ]; 56751898Smckusick FILE *exp_file; 56838460Smckusick 56938460Smckusick /* 57038460Smckusick * Get the export list 57138460Smckusick */ 57246709Sbostic void 57338460Smckusick get_exportlist() 57438460Smckusick { 57566163Spendry struct exportlist *ep, *ep2; 57666163Spendry struct grouplist *grp, *tgrp; 57751898Smckusick struct exportlist **epp; 57851898Smckusick struct dirlist *dirhead; 57952109Smckusick struct statfs fsb, *fsp; 58051898Smckusick struct hostent *hpe; 58151898Smckusick struct ucred anon; 58253150Smckusick char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 58353150Smckusick int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 58438460Smckusick 58538460Smckusick /* 58638460Smckusick * First, get rid of the old list 58738460Smckusick */ 58851898Smckusick ep = exphead; 58951898Smckusick while (ep) { 59038460Smckusick ep2 = ep; 59138460Smckusick ep = ep->ex_next; 59244015Smckusick free_exp(ep2); 59338460Smckusick } 59466163Spendry exphead = (struct exportlist *)NULL; 59538460Smckusick 59651898Smckusick grp = grphead; 59751898Smckusick while (grp) { 59851898Smckusick tgrp = grp; 59951898Smckusick grp = grp->gr_next; 60051898Smckusick free_grp(tgrp); 60151667Smckusick } 60266163Spendry grphead = (struct grouplist *)NULL; 60351667Smckusick 60438460Smckusick /* 60552109Smckusick * And delete exports that are in the kernel for all local 60652109Smckusick * file systems. 60752109Smckusick * XXX: Should know how to handle all local exportable file systems 60852109Smckusick * instead of just MOUNT_UFS. 60952109Smckusick */ 61053214Smckusick num = getmntinfo(&fsp, MNT_NOWAIT); 61152109Smckusick for (i = 0; i < num; i++) { 61265713Shibler union { 61365713Shibler struct ufs_args ua; 61465713Shibler struct iso_args ia; 61565713Shibler struct mfs_args ma; 61665713Shibler } targs; 61765713Shibler 61865713Shibler switch (fsp->f_type) { 61965863Sbostic case MOUNT_MFS: 62065713Shibler case MOUNT_UFS: 62165863Sbostic case MOUNT_CD9660: 62265863Sbostic targs.ua.fspec = NULL; 62365713Shibler targs.ua.export.ex_flags = MNT_DELEXPORT; 62452109Smckusick if (mount(fsp->f_type, fsp->f_mntonname, 62565713Shibler fsp->f_flags | MNT_UPDATE, 62665713Shibler (caddr_t)&targs) < 0) 62765713Shibler syslog(LOG_ERR, "Can't delete exports for %s", 62852109Smckusick fsp->f_mntonname); 62952109Smckusick } 63052109Smckusick fsp++; 63152109Smckusick } 63252109Smckusick 63352109Smckusick /* 63438460Smckusick * Read in the exports file and build the list, calling 63551667Smckusick * mount() as we go along to push the export rules into the kernel. 63638460Smckusick */ 63751898Smckusick if ((exp_file = fopen(exname, "r")) == NULL) { 63838460Smckusick syslog(LOG_ERR, "Can't open %s", exname); 63938460Smckusick exit(2); 64038460Smckusick } 64166163Spendry dirhead = (struct dirlist *)NULL; 64251898Smckusick while (get_line()) { 64351667Smckusick if (debug) 64451667Smckusick fprintf(stderr,"Got line %s\n",line); 64538460Smckusick cp = line; 64638460Smckusick nextfield(&cp, &endcp); 64751667Smckusick if (*cp == '#') 64851667Smckusick goto nextline; 64951898Smckusick 65051898Smckusick /* 65151898Smckusick * Set defaults. 65251898Smckusick */ 65351898Smckusick has_host = FALSE; 65451898Smckusick anon = def_anon; 65551667Smckusick exflags = MNT_EXPORTED; 65651898Smckusick got_nondir = 0; 65751898Smckusick opt_flags = 0; 65866163Spendry ep = (struct exportlist *)NULL; 65944015Smckusick 66044015Smckusick /* 66144015Smckusick * Create new exports list entry 66244015Smckusick */ 66338460Smckusick len = endcp-cp; 66453150Smckusick tgrp = grp = get_grp(); 66551898Smckusick while (len > 0) { 66651898Smckusick if (len > RPCMNT_NAMELEN) { 66753150Smckusick getexp_err(ep, tgrp); 66851898Smckusick goto nextline; 66951667Smckusick } 67045271Smckusick if (*cp == '-') { 67166163Spendry if (ep == (struct exportlist *)NULL) { 67253150Smckusick getexp_err(ep, tgrp); 67351898Smckusick goto nextline; 67451898Smckusick } 67551898Smckusick if (debug) 67651898Smckusick fprintf(stderr, "doing opt %s\n", cp); 67751898Smckusick got_nondir = 1; 67851898Smckusick if (do_opt(&cp, &endcp, ep, grp, &has_host, 67951898Smckusick &exflags, &anon)) { 68053150Smckusick getexp_err(ep, tgrp); 68151898Smckusick goto nextline; 68251898Smckusick } 68351898Smckusick } else if (*cp == '/') { 68451898Smckusick savedc = *endcp; 68551898Smckusick *endcp = '\0'; 68665940Sbostic if (check_dirpath(cp) && 68751898Smckusick statfs(cp, &fsb) >= 0) { 68851898Smckusick if (got_nondir) { 68951898Smckusick syslog(LOG_ERR, "Dirs must be first"); 69053150Smckusick getexp_err(ep, tgrp); 69151898Smckusick goto nextline; 69251898Smckusick } 69351898Smckusick if (ep) { 69451898Smckusick if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 69551898Smckusick ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 69653150Smckusick getexp_err(ep, tgrp); 69751898Smckusick goto nextline; 69851898Smckusick } 69951667Smckusick } else { 70051898Smckusick /* 70151898Smckusick * See if this directory is already 70251898Smckusick * in the list. 70351898Smckusick */ 70451898Smckusick ep = ex_search(&fsb.f_fsid); 70566163Spendry if (ep == (struct exportlist *)NULL) { 70651898Smckusick ep = get_exp(); 70751898Smckusick ep->ex_fs = fsb.f_fsid; 70851898Smckusick ep->ex_fsdir = (char *) 70951898Smckusick malloc(strlen(fsb.f_mntonname) + 1); 71051898Smckusick if (ep->ex_fsdir) 71151898Smckusick strcpy(ep->ex_fsdir, 71251898Smckusick fsb.f_mntonname); 71351898Smckusick else 71451898Smckusick out_of_mem(); 71551898Smckusick if (debug) 71651898Smckusick fprintf(stderr, 71751898Smckusick "Making new ep fs=0x%x,0x%x\n", 71851898Smckusick fsb.f_fsid.val[0], 71951898Smckusick fsb.f_fsid.val[1]); 72051898Smckusick } else if (debug) 72151898Smckusick fprintf(stderr, 72251898Smckusick "Found ep fs=0x%x,0x%x\n", 72351898Smckusick fsb.f_fsid.val[0], 72451898Smckusick fsb.f_fsid.val[1]); 72538460Smckusick } 72651898Smckusick 72751898Smckusick /* 72851898Smckusick * Add dirpath to export mount point. 72951898Smckusick */ 73051898Smckusick dirp = add_expdir(&dirhead, cp, len); 73151898Smckusick dirplen = len; 73251898Smckusick } else { 73353150Smckusick getexp_err(ep, tgrp); 73451898Smckusick goto nextline; 73551898Smckusick } 73651898Smckusick *endcp = savedc; 73751898Smckusick } else { 73851898Smckusick savedc = *endcp; 73951898Smckusick *endcp = '\0'; 74051898Smckusick got_nondir = 1; 74166163Spendry if (ep == (struct exportlist *)NULL) { 74253150Smckusick getexp_err(ep, tgrp); 74351898Smckusick goto nextline; 74451898Smckusick } 74553150Smckusick 74653150Smckusick /* 74753150Smckusick * Get the host or netgroup. 74853150Smckusick */ 74953150Smckusick setnetgrent(cp); 75053150Smckusick netgrp = getnetgrent(&hst, &usr, &dom); 75153150Smckusick do { 75253150Smckusick if (has_host) { 75353150Smckusick grp->gr_next = get_grp(); 75453150Smckusick grp = grp->gr_next; 75553150Smckusick } 75653150Smckusick if (netgrp) { 75753150Smckusick if (get_host(hst, grp)) { 75853150Smckusick syslog(LOG_ERR, "Bad netgroup %s", cp); 75953150Smckusick getexp_err(ep, tgrp); 76053150Smckusick goto nextline; 76153150Smckusick } 76253150Smckusick } else if (get_host(cp, grp)) { 76353150Smckusick getexp_err(ep, tgrp); 76453150Smckusick goto nextline; 76553150Smckusick } 76653150Smckusick has_host = TRUE; 76753150Smckusick } while (netgrp && getnetgrent(&hst, &usr, &dom)); 76853150Smckusick endnetgrent(); 76951898Smckusick *endcp = savedc; 77038460Smckusick } 77138460Smckusick cp = endcp; 77238460Smckusick nextfield(&cp, &endcp); 77345271Smckusick len = endcp - cp; 77438460Smckusick } 77551898Smckusick if (check_options(dirhead)) { 77653150Smckusick getexp_err(ep, tgrp); 77751898Smckusick goto nextline; 77851898Smckusick } 77951898Smckusick if (!has_host) { 78051898Smckusick grp->gr_type = GT_HOST; 78151667Smckusick if (debug) 78251667Smckusick fprintf(stderr,"Adding a default entry\n"); 78351667Smckusick /* add a default group and make the grp list NULL */ 78451667Smckusick hpe = (struct hostent *)malloc(sizeof(struct hostent)); 78566163Spendry if (hpe == (struct hostent *)NULL) 78651898Smckusick out_of_mem(); 78751898Smckusick hpe->h_name = "Default"; 78851667Smckusick hpe->h_addrtype = AF_INET; 78951667Smckusick hpe->h_length = sizeof (u_long); 79066163Spendry hpe->h_addr_list = (char **)NULL; 79151898Smckusick grp->gr_ptr.gt_hostent = hpe; 79253150Smckusick 79353150Smckusick /* 79453150Smckusick * Don't allow a network export coincide with a list of 79553150Smckusick * host(s) on the same line. 79653150Smckusick */ 79753150Smckusick } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 79853150Smckusick getexp_err(ep, tgrp); 79953150Smckusick goto nextline; 80051667Smckusick } 80153150Smckusick 80253150Smckusick /* 80353150Smckusick * Loop through hosts, pushing the exports into the kernel. 80453150Smckusick * After loop, tgrp points to the start of the list and 80553150Smckusick * grp points to the last entry in the list. 80653150Smckusick */ 80753150Smckusick grp = tgrp; 80853150Smckusick do { 80953150Smckusick if (do_mount(ep, grp, exflags, &anon, dirp, 81051898Smckusick dirplen, &fsb)) { 81153150Smckusick getexp_err(ep, tgrp); 81251898Smckusick goto nextline; 81353150Smckusick } 81453150Smckusick } while (grp->gr_next && (grp = grp->gr_next)); 81551898Smckusick 81651898Smckusick /* 81751898Smckusick * Success. Update the data structures. 81851898Smckusick */ 81951898Smckusick if (has_host) { 82053150Smckusick hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS)); 82151898Smckusick grp->gr_next = grphead; 82253150Smckusick grphead = tgrp; 82351898Smckusick } else { 82466163Spendry hang_dirp(dirhead, (struct grouplist *)NULL, ep, 82553150Smckusick (opt_flags & OP_ALLDIRS)); 82651898Smckusick free_grp(grp); 82751898Smckusick } 82866163Spendry dirhead = (struct dirlist *)NULL; 82951898Smckusick if ((ep->ex_flag & EX_LINKED) == 0) { 83051898Smckusick ep2 = exphead; 83151898Smckusick epp = &exphead; 83251898Smckusick 83351898Smckusick /* 83451898Smckusick * Insert in the list in alphabetical order. 83551898Smckusick */ 83651898Smckusick while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 83751898Smckusick epp = &ep2->ex_next; 83851898Smckusick ep2 = ep2->ex_next; 83951898Smckusick } 84051898Smckusick if (ep2) 84151898Smckusick ep->ex_next = ep2; 84251898Smckusick *epp = ep; 84351898Smckusick ep->ex_flag |= EX_LINKED; 84451898Smckusick } 84551898Smckusick nextline: 84651898Smckusick if (dirhead) { 84751898Smckusick free_dir(dirhead); 84866163Spendry dirhead = (struct dirlist *)NULL; 84951898Smckusick } 85051898Smckusick } 85151898Smckusick fclose(exp_file); 85251898Smckusick } 85351898Smckusick 85451898Smckusick /* 85551898Smckusick * Allocate an export list element 85651898Smckusick */ 85751898Smckusick struct exportlist * 85851898Smckusick get_exp() 85951898Smckusick { 86066163Spendry struct exportlist *ep; 86151898Smckusick 86251898Smckusick ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 86366163Spendry if (ep == (struct exportlist *)NULL) 86451898Smckusick out_of_mem(); 86551898Smckusick bzero((caddr_t)ep, sizeof (struct exportlist)); 86651898Smckusick return (ep); 86751898Smckusick } 86851898Smckusick 86951898Smckusick /* 87051898Smckusick * Allocate a group list element 87151898Smckusick */ 87251898Smckusick struct grouplist * 87351898Smckusick get_grp() 87451898Smckusick { 87566163Spendry struct grouplist *gp; 87651898Smckusick 87751898Smckusick gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 87866163Spendry if (gp == (struct grouplist *)NULL) 87951898Smckusick out_of_mem(); 88051898Smckusick bzero((caddr_t)gp, sizeof (struct grouplist)); 88151898Smckusick return (gp); 88251898Smckusick } 88351898Smckusick 88451898Smckusick /* 88551898Smckusick * Clean up upon an error in get_exportlist(). 88651898Smckusick */ 88751898Smckusick void 88851898Smckusick getexp_err(ep, grp) 88951898Smckusick struct exportlist *ep; 89051898Smckusick struct grouplist *grp; 89151898Smckusick { 89253150Smckusick struct grouplist *tgrp; 89351898Smckusick 89451898Smckusick syslog(LOG_ERR, "Bad exports list line %s", line); 89559017Smckusick if (ep && (ep->ex_flag & EX_LINKED) == 0) 89651898Smckusick free_exp(ep); 89753150Smckusick while (grp) { 89853150Smckusick tgrp = grp; 89953150Smckusick grp = grp->gr_next; 90053150Smckusick free_grp(tgrp); 90153150Smckusick } 90251898Smckusick } 90351898Smckusick 90451898Smckusick /* 90551898Smckusick * Search the export list for a matching fs. 90651898Smckusick */ 90751898Smckusick struct exportlist * 90851898Smckusick ex_search(fsid) 90952109Smckusick fsid_t *fsid; 91051898Smckusick { 91166163Spendry struct exportlist *ep; 91251898Smckusick 91351898Smckusick ep = exphead; 91451898Smckusick while (ep) { 91551898Smckusick if (ep->ex_fs.val[0] == fsid->val[0] && 91651898Smckusick ep->ex_fs.val[1] == fsid->val[1]) 91751898Smckusick return (ep); 91851898Smckusick ep = ep->ex_next; 91951898Smckusick } 92051898Smckusick return (ep); 92151898Smckusick } 92251898Smckusick 92351898Smckusick /* 92451898Smckusick * Add a directory path to the list. 92551898Smckusick */ 92651898Smckusick char * 92751898Smckusick add_expdir(dpp, cp, len) 92851898Smckusick struct dirlist **dpp; 92951898Smckusick char *cp; 93051898Smckusick int len; 93151898Smckusick { 93266163Spendry struct dirlist *dp; 93351898Smckusick 93451898Smckusick dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 93551898Smckusick dp->dp_left = *dpp; 93666163Spendry dp->dp_right = (struct dirlist *)NULL; 93751898Smckusick dp->dp_flag = 0; 93866163Spendry dp->dp_hosts = (struct hostlist *)NULL; 93951898Smckusick strcpy(dp->dp_dirp, cp); 94051898Smckusick *dpp = dp; 94151898Smckusick return (dp->dp_dirp); 94251898Smckusick } 94351898Smckusick 94451898Smckusick /* 94551898Smckusick * Hang the dir list element off the dirpath binary tree as required 94651898Smckusick * and update the entry for host. 94751898Smckusick */ 94851898Smckusick void 94951898Smckusick hang_dirp(dp, grp, ep, alldirs) 95066163Spendry struct dirlist *dp; 95151898Smckusick struct grouplist *grp; 95251898Smckusick struct exportlist *ep; 95351898Smckusick int alldirs; 95451898Smckusick { 95566163Spendry struct hostlist *hp; 95651898Smckusick struct dirlist *dp2; 95751898Smckusick 95851898Smckusick if (alldirs) { 95951898Smckusick if (ep->ex_defdir) 96051898Smckusick free((caddr_t)dp); 96151898Smckusick else 96251898Smckusick ep->ex_defdir = dp; 96366163Spendry if (grp == (struct grouplist *)NULL) 96455292Smckusick ep->ex_defdir->dp_flag |= DP_DEFSET; 96555292Smckusick else while (grp) { 96651898Smckusick hp = get_ht(); 96751898Smckusick hp->ht_grp = grp; 96851898Smckusick hp->ht_next = ep->ex_defdir->dp_hosts; 96951898Smckusick ep->ex_defdir->dp_hosts = hp; 97055292Smckusick grp = grp->gr_next; 97155292Smckusick } 97251898Smckusick } else { 97353150Smckusick 97453150Smckusick /* 97553150Smckusick * Loop throught the directories adding them to the tree. 97653150Smckusick */ 97751898Smckusick while (dp) { 97851898Smckusick dp2 = dp->dp_left; 97953150Smckusick add_dlist(&ep->ex_dirl, dp, grp); 98051898Smckusick dp = dp2; 98151898Smckusick } 98251898Smckusick } 98351898Smckusick } 98451898Smckusick 98551898Smckusick /* 98651898Smckusick * Traverse the binary tree either updating a node that is already there 98751898Smckusick * for the new directory or adding the new node. 98851898Smckusick */ 98951898Smckusick void 99053150Smckusick add_dlist(dpp, newdp, grp) 99151898Smckusick struct dirlist **dpp; 99251898Smckusick struct dirlist *newdp; 99366163Spendry struct grouplist *grp; 99451898Smckusick { 99566163Spendry struct dirlist *dp; 99666163Spendry struct hostlist *hp; 99751898Smckusick int cmp; 99851898Smckusick 99951898Smckusick dp = *dpp; 100051898Smckusick if (dp) { 100151898Smckusick cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 100251898Smckusick if (cmp > 0) { 100353150Smckusick add_dlist(&dp->dp_left, newdp, grp); 100451898Smckusick return; 100551898Smckusick } else if (cmp < 0) { 100653150Smckusick add_dlist(&dp->dp_right, newdp, grp); 100751898Smckusick return; 100851898Smckusick } else 100951898Smckusick free((caddr_t)newdp); 101051898Smckusick } else { 101151898Smckusick dp = newdp; 101266163Spendry dp->dp_left = (struct dirlist *)NULL; 101351898Smckusick *dpp = dp; 101451898Smckusick } 101553150Smckusick if (grp) { 101653150Smckusick 101753150Smckusick /* 101853150Smckusick * Hang all of the host(s) off of the directory point. 101953150Smckusick */ 102053150Smckusick do { 102153150Smckusick hp = get_ht(); 102253150Smckusick hp->ht_grp = grp; 102353150Smckusick hp->ht_next = dp->dp_hosts; 102453150Smckusick dp->dp_hosts = hp; 102553150Smckusick grp = grp->gr_next; 102653150Smckusick } while (grp); 102751898Smckusick } else 102851898Smckusick dp->dp_flag |= DP_DEFSET; 102951898Smckusick } 103051898Smckusick 103151898Smckusick /* 103251898Smckusick * Search for a dirpath on the export point. 103351898Smckusick */ 103451898Smckusick struct dirlist * 103551898Smckusick dirp_search(dp, dirpath) 103666163Spendry struct dirlist *dp; 103751898Smckusick char *dirpath; 103851898Smckusick { 103966163Spendry int cmp; 104051898Smckusick 104151898Smckusick if (dp) { 104251898Smckusick cmp = strcmp(dp->dp_dirp, dirpath); 104351898Smckusick if (cmp > 0) 104451898Smckusick return (dirp_search(dp->dp_left, dirpath)); 104551898Smckusick else if (cmp < 0) 104651898Smckusick return (dirp_search(dp->dp_right, dirpath)); 104751898Smckusick else 104851898Smckusick return (dp); 104951898Smckusick } 105051898Smckusick return (dp); 105151898Smckusick } 105251898Smckusick 105351898Smckusick /* 105451898Smckusick * Scan for a host match in a directory tree. 105551898Smckusick */ 105666163Spendry int 105751898Smckusick chk_host(dp, saddr, defsetp) 105851898Smckusick struct dirlist *dp; 105951898Smckusick u_long saddr; 106051898Smckusick int *defsetp; 106151898Smckusick { 106266163Spendry struct hostlist *hp; 106366163Spendry struct grouplist *grp; 106466163Spendry u_long **addrp; 106551898Smckusick 106651898Smckusick if (dp) { 106751898Smckusick if (dp->dp_flag & DP_DEFSET) 106851898Smckusick *defsetp = 1; 106951898Smckusick hp = dp->dp_hosts; 107051898Smckusick while (hp) { 107151898Smckusick grp = hp->ht_grp; 107251898Smckusick switch (grp->gr_type) { 107351898Smckusick case GT_HOST: 107451898Smckusick addrp = (u_long **) 107551898Smckusick grp->gr_ptr.gt_hostent->h_addr_list; 107651898Smckusick while (*addrp) { 107751898Smckusick if (**addrp == saddr) 107851898Smckusick return (1); 107951898Smckusick addrp++; 108051898Smckusick } 108151898Smckusick break; 108251898Smckusick case GT_NET: 108351898Smckusick if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 108451898Smckusick grp->gr_ptr.gt_net.nt_net) 108551898Smckusick return (1); 108651898Smckusick break; 108751898Smckusick }; 108851898Smckusick hp = hp->ht_next; 108951898Smckusick } 109051898Smckusick } 109151898Smckusick return (0); 109251898Smckusick } 109351898Smckusick 109451898Smckusick /* 109551898Smckusick * Scan tree for a host that matches the address. 109651898Smckusick */ 109766163Spendry int 109851898Smckusick scan_tree(dp, saddr) 109966163Spendry struct dirlist *dp; 110051898Smckusick u_long saddr; 110151898Smckusick { 110251898Smckusick int defset; 110351898Smckusick 110451898Smckusick if (dp) { 110551898Smckusick if (scan_tree(dp->dp_left, saddr)) 110651898Smckusick return (1); 110751898Smckusick if (chk_host(dp, saddr, &defset)) 110851898Smckusick return (1); 110951898Smckusick if (scan_tree(dp->dp_right, saddr)) 111051898Smckusick return (1); 111151898Smckusick } 111251898Smckusick return (0); 111351898Smckusick } 111451898Smckusick 111551898Smckusick /* 111651898Smckusick * Traverse the dirlist tree and free it up. 111751898Smckusick */ 111851898Smckusick void 111951898Smckusick free_dir(dp) 112066163Spendry struct dirlist *dp; 112151898Smckusick { 112251898Smckusick 112351898Smckusick if (dp) { 112451898Smckusick free_dir(dp->dp_left); 112551898Smckusick free_dir(dp->dp_right); 112651898Smckusick free_host(dp->dp_hosts); 112751898Smckusick free((caddr_t)dp); 112851898Smckusick } 112951898Smckusick } 113051898Smckusick 113151898Smckusick /* 113251898Smckusick * Parse the option string and update fields. 113351898Smckusick * Option arguments may either be -<option>=<value> or 113451898Smckusick * -<option> <value> 113551898Smckusick */ 113666163Spendry int 113751898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 113851898Smckusick char **cpp, **endcpp; 113951898Smckusick struct exportlist *ep; 114051898Smckusick struct grouplist *grp; 114151898Smckusick int *has_hostp; 114251898Smckusick int *exflagsp; 114351898Smckusick struct ucred *cr; 114451898Smckusick { 114566163Spendry char *cpoptarg, *cpoptend; 114651898Smckusick char *cp, *endcp, *cpopt, savedc, savedc2; 114751898Smckusick int allflag, usedarg; 114851898Smckusick 114951898Smckusick cpopt = *cpp; 115051898Smckusick cpopt++; 115151898Smckusick cp = *endcpp; 115251898Smckusick savedc = *cp; 115351898Smckusick *cp = '\0'; 115451898Smckusick while (cpopt && *cpopt) { 115551898Smckusick allflag = 1; 115651898Smckusick usedarg = -2; 115751898Smckusick if (cpoptend = index(cpopt, ',')) { 115851898Smckusick *cpoptend++ = '\0'; 115951898Smckusick if (cpoptarg = index(cpopt, '=')) 116051898Smckusick *cpoptarg++ = '\0'; 116151898Smckusick } else { 116251898Smckusick if (cpoptarg = index(cpopt, '=')) 116351898Smckusick *cpoptarg++ = '\0'; 116451898Smckusick else { 116551898Smckusick *cp = savedc; 116651898Smckusick nextfield(&cp, &endcp); 116751898Smckusick **endcpp = '\0'; 116851898Smckusick if (endcp > cp && *cp != '-') { 116951898Smckusick cpoptarg = cp; 117051898Smckusick savedc2 = *endcp; 117151898Smckusick *endcp = '\0'; 117251898Smckusick usedarg = 0; 117351667Smckusick } 117451667Smckusick } 117551667Smckusick } 117651898Smckusick if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 117751898Smckusick *exflagsp |= MNT_EXRDONLY; 117851898Smckusick } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 117951898Smckusick !(allflag = strcmp(cpopt, "mapall")) || 118051898Smckusick !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 118151898Smckusick usedarg++; 118251898Smckusick parsecred(cpoptarg, cr); 118351898Smckusick if (allflag == 0) { 118451898Smckusick *exflagsp |= MNT_EXPORTANON; 118551898Smckusick opt_flags |= OP_MAPALL; 118651898Smckusick } else 118751898Smckusick opt_flags |= OP_MAPROOT; 118851898Smckusick } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 118951898Smckusick *exflagsp |= MNT_EXKERB; 119051898Smckusick opt_flags |= OP_KERB; 119153150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "mask") || 119253150Smckusick !strcmp(cpopt, "m"))) { 119351898Smckusick if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 119451898Smckusick syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 119551898Smckusick return (1); 119651898Smckusick } 119751898Smckusick usedarg++; 119851898Smckusick opt_flags |= OP_MASK; 119953150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "network") || 120053150Smckusick !strcmp(cpopt, "n"))) { 120151898Smckusick if (grp->gr_type != GT_NULL) { 120251898Smckusick syslog(LOG_ERR, "Network/host conflict"); 120351898Smckusick return (1); 120451898Smckusick } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 120551898Smckusick syslog(LOG_ERR, "Bad net: %s", cpoptarg); 120651898Smckusick return (1); 120751898Smckusick } 120851898Smckusick grp->gr_type = GT_NET; 120951898Smckusick *has_hostp = 1; 121051898Smckusick usedarg++; 121151898Smckusick opt_flags |= OP_NET; 121251898Smckusick } else if (!strcmp(cpopt, "alldirs")) { 121351898Smckusick opt_flags |= OP_ALLDIRS; 121451898Smckusick #ifdef ISO 121551898Smckusick } else if (cpoptarg && !strcmp(cpopt, "iso")) { 121651898Smckusick if (get_isoaddr(cpoptarg, grp)) { 121751898Smckusick syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 121851898Smckusick return (1); 121951898Smckusick } 122051898Smckusick *has_hostp = 1; 122151898Smckusick usedarg++; 122251898Smckusick opt_flags |= OP_ISO; 122351898Smckusick #endif /* ISO */ 122451898Smckusick } else { 122551898Smckusick syslog(LOG_ERR, "Bad opt %s", cpopt); 122651898Smckusick return (1); 122751667Smckusick } 122851898Smckusick if (usedarg >= 0) { 122951898Smckusick *endcp = savedc2; 123051898Smckusick **endcpp = savedc; 123151898Smckusick if (usedarg > 0) { 123251898Smckusick *cpp = cp; 123351898Smckusick *endcpp = endcp; 123451898Smckusick } 123551898Smckusick return (0); 123651898Smckusick } 123751898Smckusick cpopt = cpoptend; 123851667Smckusick } 123951898Smckusick **endcpp = savedc; 124051898Smckusick return (0); 124151898Smckusick } 124251898Smckusick 124351898Smckusick /* 124451898Smckusick * Translate a character string to the corresponding list of network 124551898Smckusick * addresses for a hostname. 124651898Smckusick */ 124766163Spendry int 124851898Smckusick get_host(cp, grp) 124951898Smckusick char *cp; 125066163Spendry struct grouplist *grp; 125151898Smckusick { 125266163Spendry struct hostent *hp, *nhp; 125366163Spendry char **addrp, **naddrp; 125451898Smckusick struct hostent t_host; 125551898Smckusick int i; 125651898Smckusick u_long saddr; 125751898Smckusick char *aptr[2]; 125851898Smckusick 125951898Smckusick if (grp->gr_type != GT_NULL) 126051898Smckusick return (1); 126151898Smckusick if ((hp = gethostbyname(cp)) == NULL) { 126251898Smckusick if (isdigit(*cp)) { 126351898Smckusick saddr = inet_addr(cp); 126451898Smckusick if (saddr == -1) { 126551898Smckusick syslog(LOG_ERR, "Inet_addr failed"); 126651898Smckusick return (1); 126751898Smckusick } 126851898Smckusick if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 126951898Smckusick AF_INET)) == NULL) { 127051898Smckusick hp = &t_host; 127151898Smckusick hp->h_name = cp; 127251898Smckusick hp->h_addrtype = AF_INET; 127351898Smckusick hp->h_length = sizeof (u_long); 127451898Smckusick hp->h_addr_list = aptr; 127551898Smckusick aptr[0] = (char *)&saddr; 127666163Spendry aptr[1] = (char *)NULL; 127751898Smckusick } 127851898Smckusick } else { 127951898Smckusick syslog(LOG_ERR, "Gethostbyname failed"); 128051898Smckusick return (1); 128151898Smckusick } 128251898Smckusick } 128351898Smckusick grp->gr_type = GT_HOST; 128451898Smckusick nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 128551898Smckusick malloc(sizeof(struct hostent)); 128666163Spendry if (nhp == (struct hostent *)NULL) 128751898Smckusick out_of_mem(); 128851898Smckusick bcopy((caddr_t)hp, (caddr_t)nhp, 128951898Smckusick sizeof(struct hostent)); 129051898Smckusick i = strlen(hp->h_name)+1; 129151898Smckusick nhp->h_name = (char *)malloc(i); 129266163Spendry if (nhp->h_name == (char *)NULL) 129351898Smckusick out_of_mem(); 129451898Smckusick bcopy(hp->h_name, nhp->h_name, i); 129551898Smckusick addrp = hp->h_addr_list; 129651898Smckusick i = 1; 129751898Smckusick while (*addrp++) 129851898Smckusick i++; 129951898Smckusick naddrp = nhp->h_addr_list = (char **) 130051898Smckusick malloc(i*sizeof(char *)); 130166163Spendry if (naddrp == (char **)NULL) 130251898Smckusick out_of_mem(); 130351898Smckusick addrp = hp->h_addr_list; 130451898Smckusick while (*addrp) { 130551898Smckusick *naddrp = (char *) 130651898Smckusick malloc(hp->h_length); 130766163Spendry if (*naddrp == (char *)NULL) 130851898Smckusick out_of_mem(); 130951898Smckusick bcopy(*addrp, *naddrp, 131051898Smckusick hp->h_length); 131151898Smckusick addrp++; 131251898Smckusick naddrp++; 131351898Smckusick } 131466163Spendry *naddrp = (char *)NULL; 131553150Smckusick if (debug) 131653150Smckusick fprintf(stderr, "got host %s\n", hp->h_name); 131751898Smckusick return (0); 131851898Smckusick } 131951898Smckusick 132051898Smckusick /* 132151898Smckusick * Free up an exports list component 132251898Smckusick */ 132351898Smckusick void 132451898Smckusick free_exp(ep) 132566163Spendry struct exportlist *ep; 132651898Smckusick { 132751898Smckusick 132851898Smckusick if (ep->ex_defdir) { 132951898Smckusick free_host(ep->ex_defdir->dp_hosts); 133051898Smckusick free((caddr_t)ep->ex_defdir); 133151898Smckusick } 133251898Smckusick if (ep->ex_fsdir) 133351898Smckusick free(ep->ex_fsdir); 133451898Smckusick free_dir(ep->ex_dirl); 133551898Smckusick free((caddr_t)ep); 133651898Smckusick } 133751898Smckusick 133851898Smckusick /* 133951898Smckusick * Free hosts. 134051898Smckusick */ 134151898Smckusick void 134251898Smckusick free_host(hp) 134366163Spendry struct hostlist *hp; 134451898Smckusick { 134566163Spendry struct hostlist *hp2; 134651898Smckusick 134751898Smckusick while (hp) { 134851898Smckusick hp2 = hp; 134951898Smckusick hp = hp->ht_next; 135051898Smckusick free((caddr_t)hp2); 135151898Smckusick } 135251898Smckusick } 135351898Smckusick 135451898Smckusick struct hostlist * 135551898Smckusick get_ht() 135651898Smckusick { 135766163Spendry struct hostlist *hp; 135851898Smckusick 135951898Smckusick hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 136066163Spendry if (hp == (struct hostlist *)NULL) 136151898Smckusick out_of_mem(); 136266163Spendry hp->ht_next = (struct hostlist *)NULL; 136351898Smckusick return (hp); 136451898Smckusick } 136551898Smckusick 136651898Smckusick #ifdef ISO 136751898Smckusick /* 136851898Smckusick * Translate an iso address. 136951898Smckusick */ 137051898Smckusick get_isoaddr(cp, grp) 137151898Smckusick char *cp; 137251898Smckusick struct grouplist *grp; 137351898Smckusick { 137451898Smckusick struct iso_addr *isop; 137551898Smckusick struct sockaddr_iso *isoaddr; 137651898Smckusick 137751898Smckusick if (grp->gr_type != GT_NULL) 137851898Smckusick return (1); 137951898Smckusick if ((isop = iso_addr(cp)) == NULL) { 138051898Smckusick syslog(LOG_ERR, 138151898Smckusick "iso_addr failed, ignored"); 138251898Smckusick return (1); 138351898Smckusick } 138451898Smckusick isoaddr = (struct sockaddr_iso *) 138551898Smckusick malloc(sizeof (struct sockaddr_iso)); 138666163Spendry if (isoaddr == (struct sockaddr_iso *)NULL) 138751898Smckusick out_of_mem(); 138851898Smckusick bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 138951898Smckusick bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 139051898Smckusick sizeof (struct iso_addr)); 139151898Smckusick isoaddr->siso_len = sizeof (struct sockaddr_iso); 139251898Smckusick isoaddr->siso_family = AF_ISO; 139351898Smckusick grp->gr_type = GT_ISO; 139451898Smckusick grp->gr_ptr.gt_isoaddr = isoaddr; 139551898Smckusick return (0); 139651898Smckusick } 139751898Smckusick #endif /* ISO */ 139851898Smckusick 139951898Smckusick /* 140051898Smckusick * Out of memory, fatal 140151898Smckusick */ 140251898Smckusick void 140351898Smckusick out_of_mem() 140451898Smckusick { 140551898Smckusick 140651898Smckusick syslog(LOG_ERR, "Out of memory"); 140751667Smckusick exit(2); 140851667Smckusick } 140951667Smckusick 141051898Smckusick /* 141151898Smckusick * Do the mount syscall with the update flag to push the export info into 141251898Smckusick * the kernel. 141351898Smckusick */ 141466163Spendry int 141551898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 141651667Smckusick struct exportlist *ep; 141751667Smckusick struct grouplist *grp; 141851898Smckusick int exflags; 141951667Smckusick struct ucred *anoncrp; 142051898Smckusick char *dirp; 142151898Smckusick int dirplen; 142251898Smckusick struct statfs *fsb; 142351667Smckusick { 142466163Spendry char *cp = (char *)NULL; 142566163Spendry u_long **addrp; 142651898Smckusick int done; 142766163Spendry char savedc = '\0'; 142851898Smckusick struct sockaddr_in sin, imask; 142965713Shibler union { 143065713Shibler struct ufs_args ua; 143165713Shibler struct iso_args ia; 143265713Shibler struct mfs_args ma; 143365713Shibler } args; 143451898Smckusick u_long net; 143551667Smckusick 143665713Shibler args.ua.fspec = 0; 143765713Shibler args.ua.export.ex_flags = exflags; 143865713Shibler args.ua.export.ex_anon = *anoncrp; 143955878Smckusick bzero((char *)&sin, sizeof(sin)); 144055878Smckusick bzero((char *)&imask, sizeof(imask)); 144151667Smckusick sin.sin_family = AF_INET; 144251667Smckusick sin.sin_len = sizeof(sin); 144351898Smckusick imask.sin_family = AF_INET; 144451898Smckusick imask.sin_len = sizeof(sin); 144551898Smckusick if (grp->gr_type == GT_HOST) 144651667Smckusick addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 144751898Smckusick else 144866163Spendry addrp = (u_long **)NULL; 144951667Smckusick done = FALSE; 145051898Smckusick while (!done) { 145151898Smckusick switch (grp->gr_type) { 145251898Smckusick case GT_HOST: 145364903Smckusick if (addrp) { 145451712Smckusick sin.sin_addr.s_addr = **addrp; 145565713Shibler args.ua.export.ex_addrlen = sizeof(sin); 145664903Smckusick } else 145765713Shibler args.ua.export.ex_addrlen = 0; 145865713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 145965713Shibler args.ua.export.ex_masklen = 0; 146051898Smckusick break; 146151898Smckusick case GT_NET: 146251898Smckusick if (grp->gr_ptr.gt_net.nt_mask) 146351898Smckusick imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 146451898Smckusick else { 146551898Smckusick net = ntohl(grp->gr_ptr.gt_net.nt_net); 146651898Smckusick if (IN_CLASSA(net)) 146751898Smckusick imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 146851898Smckusick else if (IN_CLASSB(net)) 146951898Smckusick imask.sin_addr.s_addr = 147051898Smckusick inet_addr("255.255.0.0"); 147151898Smckusick else 147251898Smckusick imask.sin_addr.s_addr = 147351898Smckusick inet_addr("255.255.255.0"); 147451898Smckusick grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 147551898Smckusick } 147651898Smckusick sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 147765713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 147865713Shibler args.ua.export.ex_addrlen = sizeof (sin); 147965713Shibler args.ua.export.ex_mask = (struct sockaddr *)&imask; 148065713Shibler args.ua.export.ex_masklen = sizeof (imask); 148151898Smckusick break; 148251667Smckusick #ifdef ISO 148351898Smckusick case GT_ISO: 148465713Shibler args.ua.export.ex_addr = 148565713Shibler (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 148665713Shibler args.ua.export.ex_addrlen = 148765713Shibler sizeof(struct sockaddr_iso); 148865713Shibler args.ua.export.ex_masklen = 0; 148951898Smckusick break; 149051667Smckusick #endif /* ISO */ 149151898Smckusick default: 149251667Smckusick syslog(LOG_ERR, "Bad grouptype"); 149351898Smckusick if (cp) 149451898Smckusick *cp = savedc; 149551898Smckusick return (1); 149651898Smckusick }; 149752109Smckusick 149852109Smckusick /* 149952109Smckusick * XXX: 150052109Smckusick * Maybe I should just use the fsb->f_mntonname path instead 150152109Smckusick * of looping back up the dirp to the mount point?? 150252109Smckusick * Also, needs to know how to export all types of local 150352109Smckusick * exportable file systems and not just MOUNT_UFS. 150452109Smckusick */ 150552109Smckusick while (mount(fsb->f_type, dirp, 150652109Smckusick fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 150751898Smckusick if (cp) 150851898Smckusick *cp-- = savedc; 150951898Smckusick else 151051898Smckusick cp = dirp + dirplen - 1; 151151667Smckusick if (errno == EPERM) { 151251667Smckusick syslog(LOG_ERR, 151351898Smckusick "Can't change attributes for %s.\n", dirp); 151451898Smckusick return (1); 151551667Smckusick } 151651898Smckusick if (opt_flags & OP_ALLDIRS) { 151751898Smckusick syslog(LOG_ERR, "Not root dir"); 151851898Smckusick return (1); 151951898Smckusick } 152051667Smckusick /* back up over the last component */ 152151898Smckusick while (*cp == '/' && cp > dirp) 152251667Smckusick cp--; 152351898Smckusick while (*(cp - 1) != '/' && cp > dirp) 152451667Smckusick cp--; 152551898Smckusick if (cp == dirp) { 152651898Smckusick if (debug) 152751667Smckusick fprintf(stderr,"mnt unsucc\n"); 152851898Smckusick syslog(LOG_ERR, "Can't export %s", dirp); 152951898Smckusick return (1); 153051667Smckusick } 153151667Smckusick savedc = *cp; 153251667Smckusick *cp = '\0'; 153351667Smckusick } 153451898Smckusick if (addrp) { 153551667Smckusick ++addrp; 153666163Spendry if (*addrp == (u_long *)NULL) 153751667Smckusick done = TRUE; 153851898Smckusick } else 153951898Smckusick done = TRUE; 154051898Smckusick } 154151898Smckusick if (cp) 154251898Smckusick *cp = savedc; 154351898Smckusick return (0); 154451898Smckusick } 154551898Smckusick 154651898Smckusick /* 154751898Smckusick * Translate a net address. 154851898Smckusick */ 154966163Spendry int 155051898Smckusick get_net(cp, net, maskflg) 155151898Smckusick char *cp; 155251898Smckusick struct netmsk *net; 155351898Smckusick int maskflg; 155451898Smckusick { 155566163Spendry struct netent *np; 155666163Spendry long netaddr; 155751898Smckusick struct in_addr inetaddr, inetaddr2; 155851898Smckusick char *name; 155951898Smckusick 156051898Smckusick if (np = getnetbyname(cp)) 156151898Smckusick inetaddr = inet_makeaddr(np->n_net, 0); 156251898Smckusick else if (isdigit(*cp)) { 156351898Smckusick if ((netaddr = inet_network(cp)) == -1) 156451898Smckusick return (1); 156551898Smckusick inetaddr = inet_makeaddr(netaddr, 0); 156651898Smckusick /* 156751898Smckusick * Due to arbritrary subnet masks, you don't know how many 156851898Smckusick * bits to shift the address to make it into a network, 156951898Smckusick * however you do know how to make a network address into 157051898Smckusick * a host with host == 0 and then compare them. 157151898Smckusick * (What a pest) 157251898Smckusick */ 157351898Smckusick if (!maskflg) { 157451898Smckusick setnetent(0); 157551898Smckusick while (np = getnetent()) { 157651898Smckusick inetaddr2 = inet_makeaddr(np->n_net, 0); 157751898Smckusick if (inetaddr2.s_addr == inetaddr.s_addr) 157851898Smckusick break; 157951898Smckusick } 158051898Smckusick endnetent(); 158151667Smckusick } 158251898Smckusick } else 158351898Smckusick return (1); 158451898Smckusick if (maskflg) 158551898Smckusick net->nt_mask = inetaddr.s_addr; 158651898Smckusick else { 158751898Smckusick if (np) 158851898Smckusick name = np->n_name; 158951898Smckusick else 159051898Smckusick name = inet_ntoa(inetaddr); 159151898Smckusick net->nt_name = (char *)malloc(strlen(name) + 1); 159266163Spendry if (net->nt_name == (char *)NULL) 159351898Smckusick out_of_mem(); 159451898Smckusick strcpy(net->nt_name, name); 159551898Smckusick net->nt_net = inetaddr.s_addr; 159638460Smckusick } 159751898Smckusick return (0); 159838460Smckusick } 159938460Smckusick 160038460Smckusick /* 160138460Smckusick * Parse out the next white space separated field 160238460Smckusick */ 160351667Smckusick void 160438460Smckusick nextfield(cp, endcp) 160538460Smckusick char **cp; 160638460Smckusick char **endcp; 160738460Smckusick { 160866163Spendry char *p; 160938460Smckusick 161038460Smckusick p = *cp; 161138460Smckusick while (*p == ' ' || *p == '\t') 161238460Smckusick p++; 161351898Smckusick if (*p == '\n' || *p == '\0') 161438460Smckusick *cp = *endcp = p; 161551898Smckusick else { 161651898Smckusick *cp = p++; 161751898Smckusick while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 161851898Smckusick p++; 161951898Smckusick *endcp = p; 162038460Smckusick } 162138460Smckusick } 162239681Smckusick 162339681Smckusick /* 162451898Smckusick * Get an exports file line. Skip over blank lines and handle line 162551898Smckusick * continuations. 162639681Smckusick */ 162766163Spendry int 162851898Smckusick get_line() 162939681Smckusick { 163066163Spendry char *p, *cp; 163166163Spendry int len; 163251898Smckusick int totlen, cont_line; 163339681Smckusick 163451898Smckusick /* 163551898Smckusick * Loop around ignoring blank lines and getting all continuation lines. 163651898Smckusick */ 163751898Smckusick p = line; 163851898Smckusick totlen = 0; 163951898Smckusick do { 164051898Smckusick if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 164151898Smckusick return (0); 164251898Smckusick len = strlen(p); 164351898Smckusick cp = p + len - 1; 164451898Smckusick cont_line = 0; 164551898Smckusick while (cp >= p && 164651898Smckusick (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 164751898Smckusick if (*cp == '\\') 164851898Smckusick cont_line = 1; 164951898Smckusick cp--; 165051898Smckusick len--; 165151898Smckusick } 165251898Smckusick *++cp = '\0'; 165351898Smckusick if (len > 0) { 165451898Smckusick totlen += len; 165551898Smckusick if (totlen >= LINESIZ) { 165651898Smckusick syslog(LOG_ERR, "Exports line too long"); 165751898Smckusick exit(2); 165851898Smckusick } 165951898Smckusick p = cp; 166051898Smckusick } 166151898Smckusick } while (totlen == 0 || cont_line); 166251898Smckusick return (1); 166344015Smckusick } 166444015Smckusick 166551667Smckusick /* 166651667Smckusick * Parse a description of a credential. 166751667Smckusick */ 166866163Spendry void 166951667Smckusick parsecred(namelist, cr) 167051667Smckusick char *namelist; 167166163Spendry struct ucred *cr; 167251667Smckusick { 167366163Spendry char *name; 167466163Spendry int cnt; 167551667Smckusick char *names; 167651667Smckusick struct passwd *pw; 167751667Smckusick struct group *gr; 167851667Smckusick int ngroups, groups[NGROUPS + 1]; 167951667Smckusick 168051667Smckusick /* 168151667Smckusick * Set up the unpriviledged user. 168251667Smckusick */ 168351667Smckusick cr->cr_ref = 1; 168451667Smckusick cr->cr_uid = -2; 168551667Smckusick cr->cr_groups[0] = -2; 168651667Smckusick cr->cr_ngroups = 1; 168751667Smckusick /* 168851667Smckusick * Get the user's password table entry. 168951667Smckusick */ 169051667Smckusick names = strsep(&namelist, " \t\n"); 169151667Smckusick name = strsep(&names, ":"); 169251667Smckusick if (isdigit(*name) || *name == '-') 169351667Smckusick pw = getpwuid(atoi(name)); 169451667Smckusick else 169551667Smckusick pw = getpwnam(name); 169651667Smckusick /* 169751667Smckusick * Credentials specified as those of a user. 169851667Smckusick */ 169951667Smckusick if (names == NULL) { 170051667Smckusick if (pw == NULL) { 170166163Spendry syslog(LOG_ERR, "Unknown user: %s", name); 170251667Smckusick return; 170351667Smckusick } 170451667Smckusick cr->cr_uid = pw->pw_uid; 170551667Smckusick ngroups = NGROUPS + 1; 170651667Smckusick if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 170766163Spendry syslog(LOG_ERR, "Too many groups"); 170851667Smckusick /* 170951667Smckusick * Convert from int's to gid_t's and compress out duplicate 171051667Smckusick */ 171151667Smckusick cr->cr_ngroups = ngroups - 1; 171251667Smckusick cr->cr_groups[0] = groups[0]; 171351667Smckusick for (cnt = 2; cnt < ngroups; cnt++) 171451667Smckusick cr->cr_groups[cnt - 1] = groups[cnt]; 171551667Smckusick return; 171651667Smckusick } 171751667Smckusick /* 171851667Smckusick * Explicit credential specified as a colon separated list: 171951667Smckusick * uid:gid:gid:... 172051667Smckusick */ 172151667Smckusick if (pw != NULL) 172251667Smckusick cr->cr_uid = pw->pw_uid; 172351667Smckusick else if (isdigit(*name) || *name == '-') 172451667Smckusick cr->cr_uid = atoi(name); 172551667Smckusick else { 172666163Spendry syslog(LOG_ERR, "Unknown user: %s", name); 172751667Smckusick return; 172851667Smckusick } 172951667Smckusick cr->cr_ngroups = 0; 173051667Smckusick while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 173151667Smckusick name = strsep(&names, ":"); 173251667Smckusick if (isdigit(*name) || *name == '-') { 173351667Smckusick cr->cr_groups[cr->cr_ngroups++] = atoi(name); 173451667Smckusick } else { 173551667Smckusick if ((gr = getgrnam(name)) == NULL) { 173666163Spendry syslog(LOG_ERR, "Unknown group: %s", name); 173751667Smckusick continue; 173851667Smckusick } 173951667Smckusick cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 174051667Smckusick } 174151667Smckusick } 174251667Smckusick if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 174366163Spendry syslog(LOG_ERR, "Too many groups"); 174451667Smckusick } 174551667Smckusick 174644015Smckusick #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 174744015Smckusick /* 174844015Smckusick * Routines that maintain the remote mounttab 174944015Smckusick */ 175051667Smckusick void 175151667Smckusick get_mountlist() 175244015Smckusick { 175366163Spendry struct mountlist *mlp, **mlpp; 175466163Spendry char *eos, *dirp; 175544015Smckusick int len; 175644015Smckusick char str[STRSIZ]; 175744015Smckusick FILE *mlfile; 175844015Smckusick 175951712Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 176051667Smckusick syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 176144015Smckusick return; 176244015Smckusick } 176344015Smckusick mlpp = &mlhead; 176444015Smckusick while (fgets(str, STRSIZ, mlfile) != NULL) { 176544015Smckusick if ((dirp = index(str, '\t')) == NULL && 176644015Smckusick (dirp = index(str, ' ')) == NULL) 176744015Smckusick continue; 176844015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 176944015Smckusick len = dirp-str; 177044015Smckusick if (len > RPCMNT_NAMELEN) 177144015Smckusick len = RPCMNT_NAMELEN; 177244015Smckusick bcopy(str, mlp->ml_host, len); 177344015Smckusick mlp->ml_host[len] = '\0'; 177444015Smckusick while (*dirp == '\t' || *dirp == ' ') 177544015Smckusick dirp++; 177644015Smckusick if ((eos = index(dirp, '\t')) == NULL && 177744015Smckusick (eos = index(dirp, ' ')) == NULL && 177844015Smckusick (eos = index(dirp, '\n')) == NULL) 177944015Smckusick len = strlen(dirp); 178044015Smckusick else 178144015Smckusick len = eos-dirp; 178244015Smckusick if (len > RPCMNT_PATHLEN) 178344015Smckusick len = RPCMNT_PATHLEN; 178444015Smckusick bcopy(dirp, mlp->ml_dirp, len); 178544015Smckusick mlp->ml_dirp[len] = '\0'; 178666163Spendry mlp->ml_next = (struct mountlist *)NULL; 178744015Smckusick *mlpp = mlp; 178844015Smckusick mlpp = &mlp->ml_next; 178944015Smckusick } 179044015Smckusick fclose(mlfile); 179144015Smckusick } 179244015Smckusick 179351667Smckusick void 179451667Smckusick del_mlist(hostp, dirp) 179566163Spendry char *hostp, *dirp; 179644015Smckusick { 179766163Spendry struct mountlist *mlp, **mlpp; 179851712Smckusick struct mountlist *mlp2; 179944015Smckusick FILE *mlfile; 180044015Smckusick int fnd = 0; 180144015Smckusick 180244015Smckusick mlpp = &mlhead; 180344015Smckusick mlp = mlhead; 180444015Smckusick while (mlp) { 180544015Smckusick if (!strcmp(mlp->ml_host, hostp) && 180644015Smckusick (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 180744015Smckusick fnd = 1; 180851712Smckusick mlp2 = mlp; 180951712Smckusick *mlpp = mlp = mlp->ml_next; 181051712Smckusick free((caddr_t)mlp2); 181151712Smckusick } else { 181251712Smckusick mlpp = &mlp->ml_next; 181351712Smckusick mlp = mlp->ml_next; 181439681Smckusick } 181539681Smckusick } 181644015Smckusick if (fnd) { 181744015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 181851898Smckusick syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 181944015Smckusick return; 182044015Smckusick } 182144015Smckusick mlp = mlhead; 182244015Smckusick while (mlp) { 182344015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 182444015Smckusick mlp = mlp->ml_next; 182544015Smckusick } 182644015Smckusick fclose(mlfile); 182744015Smckusick } 182839681Smckusick } 182944015Smckusick 183051667Smckusick void 183151667Smckusick add_mlist(hostp, dirp) 183266163Spendry char *hostp, *dirp; 183344015Smckusick { 183466163Spendry struct mountlist *mlp, **mlpp; 183544015Smckusick FILE *mlfile; 183644015Smckusick 183744015Smckusick mlpp = &mlhead; 183844015Smckusick mlp = mlhead; 183944015Smckusick while (mlp) { 184044015Smckusick if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 184144015Smckusick return; 184244015Smckusick mlpp = &mlp->ml_next; 184344015Smckusick mlp = mlp->ml_next; 184444015Smckusick } 184544015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 184644015Smckusick strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 184744015Smckusick mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 184844015Smckusick strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 184944015Smckusick mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 185066163Spendry mlp->ml_next = (struct mountlist *)NULL; 185144015Smckusick *mlpp = mlp; 185244015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 185351898Smckusick syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 185444015Smckusick return; 185544015Smckusick } 185644015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 185744015Smckusick fclose(mlfile); 185844015Smckusick } 185944015Smckusick 186044015Smckusick /* 186144015Smckusick * This function is called via. SIGTERM when the system is going down. 186244015Smckusick * It sends a broadcast RPCMNT_UMNTALL. 186344015Smckusick */ 186446709Sbostic void 186544015Smckusick send_umntall() 186644015Smckusick { 186744015Smckusick (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 186844015Smckusick xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 186951667Smckusick exit(0); 187044015Smckusick } 187144015Smckusick 187266163Spendry int 187344015Smckusick umntall_each(resultsp, raddr) 187444015Smckusick caddr_t resultsp; 187544015Smckusick struct sockaddr_in *raddr; 187644015Smckusick { 187744015Smckusick return (1); 187844015Smckusick } 187944015Smckusick 188044015Smckusick /* 188151667Smckusick * Free up a group list. 188251667Smckusick */ 188351667Smckusick void 188451667Smckusick free_grp(grp) 188566163Spendry struct grouplist *grp; 188651667Smckusick { 188766163Spendry char **addrp; 188851667Smckusick 188951898Smckusick if (grp->gr_type == GT_HOST) { 189051712Smckusick if (grp->gr_ptr.gt_hostent->h_name) { 189151712Smckusick addrp = grp->gr_ptr.gt_hostent->h_addr_list; 189251712Smckusick while (addrp && *addrp) 189351712Smckusick free(*addrp++); 189451712Smckusick free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 189551712Smckusick free(grp->gr_ptr.gt_hostent->h_name); 189651712Smckusick } 189751667Smckusick free((caddr_t)grp->gr_ptr.gt_hostent); 189851898Smckusick } else if (grp->gr_type == GT_NET) { 189951898Smckusick if (grp->gr_ptr.gt_net.nt_name) 190051898Smckusick free(grp->gr_ptr.gt_net.nt_name); 190151667Smckusick } 190251667Smckusick #ifdef ISO 190351898Smckusick else if (grp->gr_type == GT_ISO) 190451667Smckusick free((caddr_t)grp->gr_ptr.gt_isoaddr); 190551667Smckusick #endif 190651667Smckusick free((caddr_t)grp); 190751667Smckusick } 190851667Smckusick 190951711Smckusick #ifdef DEBUG 191051711Smckusick void 191151711Smckusick SYSLOG(int pri, const char *fmt, ...) 191251711Smckusick { 191351711Smckusick va_list ap; 191451711Smckusick 191551711Smckusick va_start(ap, fmt); 191651711Smckusick vfprintf(stderr, fmt, ap); 191751711Smckusick va_end(ap); 191851711Smckusick } 191951711Smckusick #endif /* DEBUG */ 192051898Smckusick 192151898Smckusick /* 192251898Smckusick * Check options for consistency. 192351898Smckusick */ 192466163Spendry int 192551898Smckusick check_options(dp) 192651898Smckusick struct dirlist *dp; 192751898Smckusick { 192851898Smckusick 192966163Spendry if (dp == (struct dirlist *)NULL) 193051898Smckusick return (1); 193151898Smckusick if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 193251898Smckusick (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 193351898Smckusick (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 193451898Smckusick syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 193551898Smckusick return (1); 193651898Smckusick } 193751898Smckusick if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 193851898Smckusick syslog(LOG_ERR, "-mask requires -net"); 193951898Smckusick return (1); 194051898Smckusick } 194151898Smckusick if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 194251898Smckusick syslog(LOG_ERR, "-net and -iso mutually exclusive"); 194351898Smckusick return (1); 194451898Smckusick } 194551898Smckusick if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 194651898Smckusick syslog(LOG_ERR, "-alldir has multiple directories"); 194751898Smckusick return (1); 194851898Smckusick } 194951898Smckusick return (0); 195051898Smckusick } 195165940Sbostic 195265940Sbostic /* 195365940Sbostic * Check an absolute directory path for any symbolic links. Return true 195465940Sbostic * if no symbolic links are found. 195565940Sbostic */ 195665940Sbostic int 195765940Sbostic check_dirpath(dirp) 195866163Spendry char *dirp; 195965940Sbostic { 196066163Spendry char *cp; 196165940Sbostic int ret = 1; 196265940Sbostic struct stat sb; 196365940Sbostic 196465940Sbostic cp = dirp + 1; 196565940Sbostic while (*cp && ret) { 196665940Sbostic if (*cp == '/') { 196765940Sbostic *cp = '\0'; 1968*67383Smkm if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 196965940Sbostic ret = 0; 197065940Sbostic *cp = '/'; 197165940Sbostic } 197265940Sbostic cp++; 197365940Sbostic } 1974*67383Smkm if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 197565940Sbostic ret = 0; 197665940Sbostic return (ret); 197765940Sbostic } 1978