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*68996Sbostic static char sccsid[] = "@(#)mountd.c 8.14 (Berkeley) 04/28/95"; 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> 3768645Smckusick #include <nfs/nfsproto.h> 3868645Smckusick #include <ufs/ufs/ufsmount.h> 3968645Smckusick #include <sys/../isofs/cd9660/cd9660_mount.h> /* XXX need isofs in include */ 4065863Sbostic 4166163Spendry #include <arpa/inet.h> 4266163Spendry 4366163Spendry #include <ctype.h> 4465863Sbostic #include <errno.h> 4565863Sbostic #include <grp.h> 4665863Sbostic #include <netdb.h> 4765863Sbostic #include <pwd.h> 4865863Sbostic #include <signal.h> 4965863Sbostic #include <stdio.h> 5065863Sbostic #include <stdlib.h> 5165863Sbostic #include <string.h> 5265863Sbostic #include <unistd.h> 5365863Sbostic #include "pathnames.h" 5438460Smckusick 5566163Spendry #ifdef DEBUG 5666163Spendry #include <stdarg.h> 5766163Spendry #endif 5866163Spendry 5938460Smckusick /* 6038460Smckusick * Structures for keeping the mount list and export list 6138460Smckusick */ 6238460Smckusick struct mountlist { 6344015Smckusick struct mountlist *ml_next; 6438460Smckusick char ml_host[RPCMNT_NAMELEN+1]; 6538460Smckusick char ml_dirp[RPCMNT_PATHLEN+1]; 6638460Smckusick }; 6738460Smckusick 6851898Smckusick struct dirlist { 6951898Smckusick struct dirlist *dp_left; 7051898Smckusick struct dirlist *dp_right; 7151898Smckusick int dp_flag; 7251898Smckusick struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 7351898Smckusick char dp_dirp[1]; /* Actually malloc'd to size of dir */ 7451898Smckusick }; 7551898Smckusick /* dp_flag bits */ 7651898Smckusick #define DP_DEFSET 0x1 7768645Smckusick #define DP_HOSTSET 0x2 7868645Smckusick #define DP_KERB 0x4 7951898Smckusick 8038460Smckusick struct exportlist { 8138460Smckusick struct exportlist *ex_next; 8251898Smckusick struct dirlist *ex_dirl; 8351898Smckusick struct dirlist *ex_defdir; 8451898Smckusick int ex_flag; 8551898Smckusick fsid_t ex_fs; 8651898Smckusick char *ex_fsdir; 8738460Smckusick }; 8851898Smckusick /* ex_flag bits */ 8952109Smckusick #define EX_LINKED 0x1 9038460Smckusick 9151898Smckusick struct netmsk { 9251898Smckusick u_long nt_net; 9351898Smckusick u_long nt_mask; 9451898Smckusick char *nt_name; 9551898Smckusick }; 9651898Smckusick 9751667Smckusick union grouptypes { 9851667Smckusick struct hostent *gt_hostent; 9951898Smckusick struct netmsk gt_net; 10051667Smckusick #ifdef ISO 10151667Smckusick struct sockaddr_iso *gt_isoaddr; 10251667Smckusick #endif 10351667Smckusick }; 10451667Smckusick 10538460Smckusick struct grouplist { 10651898Smckusick int gr_type; 10751667Smckusick union grouptypes gr_ptr; 10838460Smckusick struct grouplist *gr_next; 10938460Smckusick }; 11051898Smckusick /* Group types */ 11151898Smckusick #define GT_NULL 0x0 11251898Smckusick #define GT_HOST 0x1 11351898Smckusick #define GT_NET 0x2 11451898Smckusick #define GT_ISO 0x4 11538460Smckusick 11651898Smckusick struct hostlist { 11768645Smckusick int ht_flag; /* Uses DP_xx bits */ 11851898Smckusick struct grouplist *ht_grp; 11951898Smckusick struct hostlist *ht_next; 12051667Smckusick }; 12151667Smckusick 12268645Smckusick struct fhreturn { 12368645Smckusick int fhr_flag; 12468645Smckusick int fhr_vers; 12568645Smckusick nfsfh_t fhr_fh; 12668645Smckusick }; 12768645Smckusick 12838460Smckusick /* Global defs */ 12966163Spendry char *add_expdir __P((struct dirlist **, char *, int)); 13066163Spendry void add_dlist __P((struct dirlist **, struct dirlist *, 13168645Smckusick struct grouplist *, int)); 13266163Spendry void add_mlist __P((char *, char *)); 13366163Spendry int check_dirpath __P((char *)); 13466163Spendry int check_options __P((struct dirlist *)); 13568645Smckusick int chk_host __P((struct dirlist *, u_long, int *, int *)); 13666163Spendry void del_mlist __P((char *, char *)); 13766163Spendry struct dirlist *dirp_search __P((struct dirlist *, char *)); 13866163Spendry int do_mount __P((struct exportlist *, struct grouplist *, int, 13968645Smckusick struct ucred *, char *, int, struct statfs *)); 14066163Spendry int do_opt __P((char **, char **, struct exportlist *, struct grouplist *, 14166163Spendry int *, int *, struct ucred *)); 14266163Spendry struct exportlist *ex_search __P((fsid_t *)); 14366163Spendry struct exportlist *get_exp __P((void)); 14466163Spendry void free_dir __P((struct dirlist *)); 14566163Spendry void free_exp __P((struct exportlist *)); 14666163Spendry void free_grp __P((struct grouplist *)); 14766163Spendry void free_host __P((struct hostlist *)); 14866163Spendry void get_exportlist __P((void)); 14966163Spendry int get_host __P((char *, struct grouplist *)); 15068645Smckusick int get_num __P((char *)); 15166163Spendry struct hostlist *get_ht __P((void)); 15266163Spendry int get_line __P((void)); 15366163Spendry void get_mountlist __P((void)); 15466163Spendry int get_net __P((char *, struct netmsk *, int)); 15566163Spendry void getexp_err __P((struct exportlist *, struct grouplist *)); 15666163Spendry struct grouplist *get_grp __P((void)); 15766163Spendry void hang_dirp __P((struct dirlist *, struct grouplist *, 15866163Spendry struct exportlist *, int)); 15966163Spendry void mntsrv __P((struct svc_req *, SVCXPRT *)); 16066163Spendry void nextfield __P((char **, char **)); 16166163Spendry void out_of_mem __P((void)); 16266163Spendry void parsecred __P((char *, struct ucred *)); 16366163Spendry int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *)); 16466163Spendry int scan_tree __P((struct dirlist *, u_long)); 16566163Spendry void send_umntall __P((void)); 16666163Spendry int umntall_each __P((caddr_t, struct sockaddr_in *)); 16766163Spendry int xdr_dir __P((XDR *, char *)); 16866163Spendry int xdr_explist __P((XDR *, caddr_t)); 16968645Smckusick int xdr_fhs __P((XDR *, caddr_t)); 17066163Spendry int xdr_mlist __P((XDR *, caddr_t)); 17166163Spendry 17266163Spendry /* C library */ 17366163Spendry int getnetgrent(); 17466163Spendry void endnetgrent(); 17566163Spendry void setnetgrent(); 17666163Spendry 17751667Smckusick #ifdef ISO 17851667Smckusick struct iso_addr *iso_addr(); 17951667Smckusick #endif 18066163Spendry 18151898Smckusick struct exportlist *exphead; 18244015Smckusick struct mountlist *mlhead; 18351898Smckusick struct grouplist *grphead; 18438460Smckusick char exname[MAXPATHLEN]; 18551667Smckusick struct ucred def_anon = { 18666163Spendry 1, 18751667Smckusick (uid_t) -2, 18851667Smckusick 1, 18966163Spendry { (gid_t) -2 } 19051667Smckusick }; 19167701Smckusick int resvport_only = 1; 19268645Smckusick int dir_only = 1; 19351898Smckusick int opt_flags; 19451898Smckusick /* Bits for above */ 19551898Smckusick #define OP_MAPROOT 0x01 19651898Smckusick #define OP_MAPALL 0x02 19751898Smckusick #define OP_KERB 0x04 19851898Smckusick #define OP_MASK 0x08 19951898Smckusick #define OP_NET 0x10 20051898Smckusick #define OP_ISO 0x20 20151898Smckusick #define OP_ALLDIRS 0x40 20251898Smckusick 20338460Smckusick #ifdef DEBUG 20438460Smckusick int debug = 1; 20551711Smckusick void SYSLOG __P((int, const char *, ...)); 20651711Smckusick #define syslog SYSLOG 20738460Smckusick #else 20838460Smckusick int debug = 0; 20938460Smckusick #endif 21038460Smckusick 21138460Smckusick /* 21238460Smckusick * Mountd server for NFS mount protocol as described in: 21339681Smckusick * NFS: Network File System Protocol Specification, RFC1094, Appendix A 21444015Smckusick * The optional arguments are the exports file name 21539681Smckusick * default: _PATH_EXPORTS 21644015Smckusick * and "-n" to allow nonroot mount. 21738460Smckusick */ 21866163Spendry int 21938460Smckusick main(argc, argv) 22038460Smckusick int argc; 22144015Smckusick char **argv; 22238460Smckusick { 22368645Smckusick SVCXPRT *udptransp, *tcptransp; 22444015Smckusick int c; 22538460Smckusick 22668685Smckusick while ((c = getopt(argc, argv, "nr")) != EOF) 22744015Smckusick switch (c) { 22844015Smckusick case 'n': 22967701Smckusick resvport_only = 0; 23044015Smckusick break; 23168645Smckusick case 'r': 23268645Smckusick dir_only = 0; 23368645Smckusick break; 23444015Smckusick default: 23568645Smckusick fprintf(stderr, "Usage: mountd [-r] [-n] [export_file]\n"); 23644015Smckusick exit(1); 23744015Smckusick }; 23844015Smckusick argc -= optind; 23944015Smckusick argv += optind; 24066163Spendry grphead = (struct grouplist *)NULL; 24166163Spendry exphead = (struct exportlist *)NULL; 24266163Spendry mlhead = (struct mountlist *)NULL; 24344015Smckusick if (argc == 1) { 24444015Smckusick strncpy(exname, *argv, MAXPATHLEN-1); 24544015Smckusick exname[MAXPATHLEN-1] = '\0'; 24644015Smckusick } else 24744015Smckusick strcpy(exname, _PATH_EXPORTS); 24866163Spendry openlog("mountd", LOG_PID, LOG_DAEMON); 24951667Smckusick if (debug) 25051667Smckusick fprintf(stderr,"Getting export list.\n"); 25144015Smckusick get_exportlist(); 25251667Smckusick if (debug) 25351667Smckusick fprintf(stderr,"Getting mount list.\n"); 25444015Smckusick get_mountlist(); 25551667Smckusick if (debug) 25651667Smckusick fprintf(stderr,"Here we go.\n"); 25738460Smckusick if (debug == 0) { 25844690Skarels daemon(0, 0); 25938460Smckusick signal(SIGINT, SIG_IGN); 26038460Smckusick signal(SIGQUIT, SIG_IGN); 26138460Smckusick } 26266163Spendry signal(SIGHUP, (void (*) __P((int))) get_exportlist); 26366163Spendry signal(SIGTERM, (void (*) __P((int))) send_umntall); 26440494Smckusick { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 26540494Smckusick if (pidfile != NULL) { 26640494Smckusick fprintf(pidfile, "%d\n", getpid()); 26740494Smckusick fclose(pidfile); 26840494Smckusick } 26940494Smckusick } 27068645Smckusick if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL || 27168645Smckusick (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) { 27238460Smckusick syslog(LOG_ERR, "Can't create socket"); 27338460Smckusick exit(1); 27438460Smckusick } 27568645Smckusick pmap_unset(RPCPROG_MNT, 1); 27668645Smckusick pmap_unset(RPCPROG_MNT, 3); 27768645Smckusick if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) || 27868645Smckusick !svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) || 27968645Smckusick !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP) || 28068645Smckusick !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) { 28138460Smckusick syslog(LOG_ERR, "Can't register mount"); 28238460Smckusick exit(1); 28338460Smckusick } 28438460Smckusick svc_run(); 28538460Smckusick syslog(LOG_ERR, "Mountd died"); 28644690Skarels exit(1); 28738460Smckusick } 28838460Smckusick 28938460Smckusick /* 29038460Smckusick * The mount rpc service 29138460Smckusick */ 29266163Spendry void 29338460Smckusick mntsrv(rqstp, transp) 29466163Spendry struct svc_req *rqstp; 29566163Spendry SVCXPRT *transp; 29638460Smckusick { 29766163Spendry struct exportlist *ep; 29866163Spendry struct dirlist *dp; 29968645Smckusick struct fhreturn fhr; 30038460Smckusick struct stat stb; 30151898Smckusick struct statfs fsb; 30238460Smckusick struct hostent *hp; 30339681Smckusick u_long saddr; 30467701Smckusick u_short sport; 30568645Smckusick char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 30668685Smckusick int bad = ENOENT, defset, hostset; 30768685Smckusick sigset_t sighup_mask; 30838460Smckusick 30968685Smckusick sigemptyset(&sighup_mask); 31068685Smckusick sigaddset(&sighup_mask, SIGHUP); 31139681Smckusick saddr = transp->xp_raddr.sin_addr.s_addr; 31267701Smckusick sport = ntohs(transp->xp_raddr.sin_port); 31366163Spendry hp = (struct hostent *)NULL; 31438460Smckusick switch (rqstp->rq_proc) { 31539681Smckusick case NULLPROC: 31666163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 31739681Smckusick syslog(LOG_ERR, "Can't send reply"); 31839681Smckusick return; 31938460Smckusick case RPCMNT_MOUNT: 32067701Smckusick if (sport >= IPPORT_RESERVED && resvport_only) { 32139681Smckusick svcerr_weakauth(transp); 32239681Smckusick return; 32339681Smckusick } 32451667Smckusick if (!svc_getargs(transp, xdr_dir, rpcpath)) { 32538460Smckusick svcerr_decode(transp); 32638460Smckusick return; 32738460Smckusick } 32838460Smckusick 32951667Smckusick /* 33068645Smckusick * Get the real pathname and make sure it is a directory 33168645Smckusick * or a regular file if the -r option was specified 33268645Smckusick * and it exists. 33351667Smckusick */ 33451898Smckusick if (realpath(rpcpath, dirpath) == 0 || 33551898Smckusick stat(dirpath, &stb) < 0 || 33668645Smckusick (!S_ISDIR(stb.st_mode) && 33768645Smckusick (dir_only || !S_ISREG(stb.st_mode))) || 33851898Smckusick statfs(dirpath, &fsb) < 0) { 33951667Smckusick chdir("/"); /* Just in case realpath doesn't */ 34051667Smckusick if (debug) 34151898Smckusick fprintf(stderr, "stat failed on %s\n", dirpath); 34238460Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 34338460Smckusick syslog(LOG_ERR, "Can't send reply"); 34438460Smckusick return; 34538460Smckusick } 34638460Smckusick 34738460Smckusick /* Check in the exports list */ 34868685Smckusick sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 34951898Smckusick ep = ex_search(&fsb.f_fsid); 35068645Smckusick hostset = defset = 0; 35168645Smckusick if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 35251898Smckusick ((dp = dirp_search(ep->ex_dirl, dirpath)) && 35368645Smckusick chk_host(dp, saddr, &defset, &hostset)) || 35451898Smckusick (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 35551898Smckusick scan_tree(ep->ex_dirl, saddr) == 0))) { 35668645Smckusick if (hostset & DP_HOSTSET) 35768645Smckusick fhr.fhr_flag = hostset; 35868645Smckusick else 35968645Smckusick fhr.fhr_flag = defset; 36068645Smckusick fhr.fhr_vers = rqstp->rq_vers; 36151667Smckusick /* Get the file handle */ 362*68996Sbostic memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 36368645Smckusick if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 36451667Smckusick bad = errno; 36551898Smckusick syslog(LOG_ERR, "Can't get fh for %s", dirpath); 36651667Smckusick if (!svc_sendreply(transp, xdr_long, 36751667Smckusick (caddr_t)&bad)) 36851667Smckusick syslog(LOG_ERR, "Can't send reply"); 36968685Smckusick sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 37051667Smckusick return; 37151667Smckusick } 37268645Smckusick if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr)) 37338460Smckusick syslog(LOG_ERR, "Can't send reply"); 37451667Smckusick if (hp == NULL) 37551667Smckusick hp = gethostbyaddr((caddr_t)&saddr, 37651667Smckusick sizeof(saddr), AF_INET); 37751667Smckusick if (hp) 37851667Smckusick add_mlist(hp->h_name, dirpath); 37951667Smckusick else 38051667Smckusick add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 38151667Smckusick dirpath); 38251667Smckusick if (debug) 38351667Smckusick fprintf(stderr,"Mount successfull.\n"); 38451898Smckusick } else { 38551898Smckusick bad = EACCES; 38651898Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 38751898Smckusick syslog(LOG_ERR, "Can't send reply"); 38838460Smckusick } 38968685Smckusick sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 39038460Smckusick return; 39138460Smckusick case RPCMNT_DUMP: 39266163Spendry if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) 39338460Smckusick syslog(LOG_ERR, "Can't send reply"); 39438460Smckusick return; 39538460Smckusick case RPCMNT_UMOUNT: 39667701Smckusick if (sport >= IPPORT_RESERVED && resvport_only) { 39739681Smckusick svcerr_weakauth(transp); 39839681Smckusick return; 39939681Smckusick } 40038460Smckusick if (!svc_getargs(transp, xdr_dir, dirpath)) { 40138460Smckusick svcerr_decode(transp); 40238460Smckusick return; 40338460Smckusick } 40466163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 40538460Smckusick syslog(LOG_ERR, "Can't send reply"); 40644015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 40744015Smckusick if (hp) 40844015Smckusick del_mlist(hp->h_name, dirpath); 40951667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 41038460Smckusick return; 41138460Smckusick case RPCMNT_UMNTALL: 41267701Smckusick if (sport >= IPPORT_RESERVED && resvport_only) { 41339681Smckusick svcerr_weakauth(transp); 41439681Smckusick return; 41539681Smckusick } 41666163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 41738460Smckusick syslog(LOG_ERR, "Can't send reply"); 41844015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 41944015Smckusick if (hp) 42066163Spendry del_mlist(hp->h_name, (char *)NULL); 42166163Spendry del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL); 42238460Smckusick return; 42338460Smckusick case RPCMNT_EXPORT: 42466163Spendry if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) 42538460Smckusick syslog(LOG_ERR, "Can't send reply"); 42638460Smckusick return; 42738460Smckusick default: 42838460Smckusick svcerr_noproc(transp); 42938460Smckusick return; 43038460Smckusick } 43138460Smckusick } 43238460Smckusick 43338460Smckusick /* 43438460Smckusick * Xdr conversion for a dirpath string 43538460Smckusick */ 43666163Spendry int 43738460Smckusick xdr_dir(xdrsp, dirp) 43838460Smckusick XDR *xdrsp; 43938460Smckusick char *dirp; 44038460Smckusick { 44138460Smckusick return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 44238460Smckusick } 44338460Smckusick 44438460Smckusick /* 44568645Smckusick * Xdr routine to generate file handle reply 44638460Smckusick */ 44766163Spendry int 44868645Smckusick xdr_fhs(xdrsp, cp) 44938460Smckusick XDR *xdrsp; 45068645Smckusick caddr_t cp; 45138460Smckusick { 45268645Smckusick register struct fhreturn *fhrp = (struct fhreturn *)cp; 45368645Smckusick long ok = 0, len, auth; 45438460Smckusick 45538460Smckusick if (!xdr_long(xdrsp, &ok)) 45638460Smckusick return (0); 45768645Smckusick switch (fhrp->fhr_vers) { 45868645Smckusick case 1: 45968645Smckusick return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 46068645Smckusick case 3: 46168645Smckusick len = NFSX_V3FH; 46268645Smckusick if (!xdr_long(xdrsp, &len)) 46368645Smckusick return (0); 46468645Smckusick if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 46568645Smckusick return (0); 46668645Smckusick if (fhrp->fhr_flag & DP_KERB) 46768645Smckusick auth = RPCAUTH_KERB4; 46868645Smckusick else 46968645Smckusick auth = RPCAUTH_UNIX; 47068645Smckusick len = 1; 47168645Smckusick if (!xdr_long(xdrsp, &len)) 47268645Smckusick return (0); 47368645Smckusick return (xdr_long(xdrsp, &auth)); 47468645Smckusick }; 47568645Smckusick return (0); 47638460Smckusick } 47738460Smckusick 47866163Spendry int 47938460Smckusick xdr_mlist(xdrsp, cp) 48038460Smckusick XDR *xdrsp; 48138460Smckusick caddr_t cp; 48238460Smckusick { 48366163Spendry struct mountlist *mlp; 48438460Smckusick int true = 1; 48538460Smckusick int false = 0; 48638460Smckusick char *strp; 48738460Smckusick 48844015Smckusick mlp = mlhead; 48944015Smckusick while (mlp) { 49044015Smckusick if (!xdr_bool(xdrsp, &true)) 49144015Smckusick return (0); 49244015Smckusick strp = &mlp->ml_host[0]; 49344015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 49444015Smckusick return (0); 49544015Smckusick strp = &mlp->ml_dirp[0]; 49644015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 49744015Smckusick return (0); 49844015Smckusick mlp = mlp->ml_next; 49938460Smckusick } 50038460Smckusick if (!xdr_bool(xdrsp, &false)) 50138460Smckusick return (0); 50238460Smckusick return (1); 50338460Smckusick } 50438460Smckusick 50538460Smckusick /* 50638460Smckusick * Xdr conversion for export list 50738460Smckusick */ 50866163Spendry int 50938460Smckusick xdr_explist(xdrsp, cp) 51038460Smckusick XDR *xdrsp; 51138460Smckusick caddr_t cp; 51238460Smckusick { 51366163Spendry struct exportlist *ep; 51438460Smckusick int false = 0; 51568685Smckusick int putdef; 51668685Smckusick sigset_t sighup_mask; 51738460Smckusick 51868685Smckusick sigemptyset(&sighup_mask); 51968685Smckusick sigaddset(&sighup_mask, SIGHUP); 52068685Smckusick sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 52151898Smckusick ep = exphead; 52251898Smckusick while (ep) { 52364903Smckusick putdef = 0; 52464903Smckusick if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 52538460Smckusick goto errout; 52664903Smckusick if (ep->ex_defdir && putdef == 0 && 52766163Spendry put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 52864903Smckusick &putdef)) 52964903Smckusick goto errout; 53038460Smckusick ep = ep->ex_next; 53138460Smckusick } 53268685Smckusick sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 53338460Smckusick if (!xdr_bool(xdrsp, &false)) 53438460Smckusick return (0); 53538460Smckusick return (1); 53638460Smckusick errout: 53768685Smckusick sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 53838460Smckusick return (0); 53938460Smckusick } 54038460Smckusick 54151898Smckusick /* 54251898Smckusick * Called from xdr_explist() to traverse the tree and export the 54351898Smckusick * directory paths. 54451898Smckusick */ 54566163Spendry int 54664903Smckusick put_exlist(dp, xdrsp, adp, putdefp) 54766163Spendry struct dirlist *dp; 54851898Smckusick XDR *xdrsp; 54951898Smckusick struct dirlist *adp; 55064903Smckusick int *putdefp; 55151898Smckusick { 55266163Spendry struct grouplist *grp; 55366163Spendry struct hostlist *hp; 55451898Smckusick int true = 1; 55551898Smckusick int false = 0; 55651898Smckusick int gotalldir = 0; 55751898Smckusick char *strp; 55851898Smckusick 55951898Smckusick if (dp) { 56064903Smckusick if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 56151898Smckusick return (1); 56251898Smckusick if (!xdr_bool(xdrsp, &true)) 56351898Smckusick return (1); 56451898Smckusick strp = dp->dp_dirp; 56551898Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 56651898Smckusick return (1); 56764903Smckusick if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 56851898Smckusick gotalldir = 1; 56964903Smckusick *putdefp = 1; 57064903Smckusick } 57151898Smckusick if ((dp->dp_flag & DP_DEFSET) == 0 && 57251898Smckusick (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 57351898Smckusick hp = dp->dp_hosts; 57451898Smckusick while (hp) { 57551898Smckusick grp = hp->ht_grp; 57651898Smckusick if (grp->gr_type == GT_HOST) { 57751898Smckusick if (!xdr_bool(xdrsp, &true)) 57851898Smckusick return (1); 57951898Smckusick strp = grp->gr_ptr.gt_hostent->h_name; 58051898Smckusick if (!xdr_string(xdrsp, &strp, 58151898Smckusick RPCMNT_NAMELEN)) 58251898Smckusick return (1); 58351898Smckusick } else if (grp->gr_type == GT_NET) { 58451898Smckusick if (!xdr_bool(xdrsp, &true)) 58551898Smckusick return (1); 58651898Smckusick strp = grp->gr_ptr.gt_net.nt_name; 58751898Smckusick if (!xdr_string(xdrsp, &strp, 58851898Smckusick RPCMNT_NAMELEN)) 58951898Smckusick return (1); 59051898Smckusick } 59151898Smckusick hp = hp->ht_next; 59266163Spendry if (gotalldir && hp == (struct hostlist *)NULL) { 59351898Smckusick hp = adp->dp_hosts; 59451898Smckusick gotalldir = 0; 59551898Smckusick } 59651898Smckusick } 59751898Smckusick } 59851898Smckusick if (!xdr_bool(xdrsp, &false)) 59951898Smckusick return (1); 60064903Smckusick if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 60151898Smckusick return (1); 60251898Smckusick } 60351898Smckusick return (0); 60451898Smckusick } 60551898Smckusick 60638460Smckusick #define LINESIZ 10240 60738460Smckusick char line[LINESIZ]; 60851898Smckusick FILE *exp_file; 60938460Smckusick 61038460Smckusick /* 61138460Smckusick * Get the export list 61238460Smckusick */ 61346709Sbostic void 61438460Smckusick get_exportlist() 61538460Smckusick { 61666163Spendry struct exportlist *ep, *ep2; 61766163Spendry struct grouplist *grp, *tgrp; 61851898Smckusick struct exportlist **epp; 61951898Smckusick struct dirlist *dirhead; 62052109Smckusick struct statfs fsb, *fsp; 62151898Smckusick struct hostent *hpe; 62251898Smckusick struct ucred anon; 62353150Smckusick char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 62453150Smckusick int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 62538460Smckusick 62638460Smckusick /* 62738460Smckusick * First, get rid of the old list 62838460Smckusick */ 62951898Smckusick ep = exphead; 63051898Smckusick while (ep) { 63138460Smckusick ep2 = ep; 63238460Smckusick ep = ep->ex_next; 63344015Smckusick free_exp(ep2); 63438460Smckusick } 63566163Spendry exphead = (struct exportlist *)NULL; 63638460Smckusick 63751898Smckusick grp = grphead; 63851898Smckusick while (grp) { 63951898Smckusick tgrp = grp; 64051898Smckusick grp = grp->gr_next; 64151898Smckusick free_grp(tgrp); 64251667Smckusick } 64366163Spendry grphead = (struct grouplist *)NULL; 64451667Smckusick 64538460Smckusick /* 64652109Smckusick * And delete exports that are in the kernel for all local 64752109Smckusick * file systems. 64852109Smckusick * XXX: Should know how to handle all local exportable file systems 64968645Smckusick * instead of just "ufs". 65052109Smckusick */ 65153214Smckusick num = getmntinfo(&fsp, MNT_NOWAIT); 65252109Smckusick for (i = 0; i < num; i++) { 65365713Shibler union { 65465713Shibler struct ufs_args ua; 65565713Shibler struct iso_args ia; 65665713Shibler struct mfs_args ma; 65765713Shibler } targs; 65865713Shibler 65968645Smckusick if (!strcmp(fsp->f_fstypename, "mfs") || 66068645Smckusick !strcmp(fsp->f_fstypename, "ufs") || 66168645Smckusick !strcmp(fsp->f_fstypename, "cd9660")) { 66265863Sbostic targs.ua.fspec = NULL; 66365713Shibler targs.ua.export.ex_flags = MNT_DELEXPORT; 66468645Smckusick if (mount(fsp->f_fstypename, fsp->f_mntonname, 66565713Shibler fsp->f_flags | MNT_UPDATE, 66665713Shibler (caddr_t)&targs) < 0) 66765713Shibler syslog(LOG_ERR, "Can't delete exports for %s", 66852109Smckusick fsp->f_mntonname); 66952109Smckusick } 67052109Smckusick fsp++; 67152109Smckusick } 67252109Smckusick 67352109Smckusick /* 67438460Smckusick * Read in the exports file and build the list, calling 67551667Smckusick * mount() as we go along to push the export rules into the kernel. 67638460Smckusick */ 67751898Smckusick if ((exp_file = fopen(exname, "r")) == NULL) { 67838460Smckusick syslog(LOG_ERR, "Can't open %s", exname); 67938460Smckusick exit(2); 68038460Smckusick } 68166163Spendry dirhead = (struct dirlist *)NULL; 68251898Smckusick while (get_line()) { 68351667Smckusick if (debug) 68451667Smckusick fprintf(stderr,"Got line %s\n",line); 68538460Smckusick cp = line; 68638460Smckusick nextfield(&cp, &endcp); 68751667Smckusick if (*cp == '#') 68851667Smckusick goto nextline; 68951898Smckusick 69051898Smckusick /* 69151898Smckusick * Set defaults. 69251898Smckusick */ 69351898Smckusick has_host = FALSE; 69451898Smckusick anon = def_anon; 69551667Smckusick exflags = MNT_EXPORTED; 69651898Smckusick got_nondir = 0; 69751898Smckusick opt_flags = 0; 69866163Spendry ep = (struct exportlist *)NULL; 69944015Smckusick 70044015Smckusick /* 70144015Smckusick * Create new exports list entry 70244015Smckusick */ 70338460Smckusick len = endcp-cp; 70453150Smckusick tgrp = grp = get_grp(); 70551898Smckusick while (len > 0) { 70651898Smckusick if (len > RPCMNT_NAMELEN) { 70753150Smckusick getexp_err(ep, tgrp); 70851898Smckusick goto nextline; 70951667Smckusick } 71045271Smckusick if (*cp == '-') { 71166163Spendry if (ep == (struct exportlist *)NULL) { 71253150Smckusick getexp_err(ep, tgrp); 71351898Smckusick goto nextline; 71451898Smckusick } 71551898Smckusick if (debug) 71651898Smckusick fprintf(stderr, "doing opt %s\n", cp); 71751898Smckusick got_nondir = 1; 71851898Smckusick if (do_opt(&cp, &endcp, ep, grp, &has_host, 71951898Smckusick &exflags, &anon)) { 72053150Smckusick getexp_err(ep, tgrp); 72151898Smckusick goto nextline; 72251898Smckusick } 72351898Smckusick } else if (*cp == '/') { 72451898Smckusick savedc = *endcp; 72551898Smckusick *endcp = '\0'; 72665940Sbostic if (check_dirpath(cp) && 72751898Smckusick statfs(cp, &fsb) >= 0) { 72851898Smckusick if (got_nondir) { 72951898Smckusick syslog(LOG_ERR, "Dirs must be first"); 73053150Smckusick getexp_err(ep, tgrp); 73151898Smckusick goto nextline; 73251898Smckusick } 73351898Smckusick if (ep) { 73451898Smckusick if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 73551898Smckusick ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 73653150Smckusick getexp_err(ep, tgrp); 73751898Smckusick goto nextline; 73851898Smckusick } 73951667Smckusick } else { 74051898Smckusick /* 74151898Smckusick * See if this directory is already 74251898Smckusick * in the list. 74351898Smckusick */ 74451898Smckusick ep = ex_search(&fsb.f_fsid); 74566163Spendry if (ep == (struct exportlist *)NULL) { 74651898Smckusick ep = get_exp(); 74751898Smckusick ep->ex_fs = fsb.f_fsid; 74851898Smckusick ep->ex_fsdir = (char *) 74951898Smckusick malloc(strlen(fsb.f_mntonname) + 1); 75051898Smckusick if (ep->ex_fsdir) 75151898Smckusick strcpy(ep->ex_fsdir, 75251898Smckusick fsb.f_mntonname); 75351898Smckusick else 75451898Smckusick out_of_mem(); 75551898Smckusick if (debug) 75651898Smckusick fprintf(stderr, 75751898Smckusick "Making new ep fs=0x%x,0x%x\n", 75851898Smckusick fsb.f_fsid.val[0], 75951898Smckusick fsb.f_fsid.val[1]); 76051898Smckusick } else if (debug) 76151898Smckusick fprintf(stderr, 76251898Smckusick "Found ep fs=0x%x,0x%x\n", 76351898Smckusick fsb.f_fsid.val[0], 76451898Smckusick fsb.f_fsid.val[1]); 76538460Smckusick } 76651898Smckusick 76751898Smckusick /* 76851898Smckusick * Add dirpath to export mount point. 76951898Smckusick */ 77051898Smckusick dirp = add_expdir(&dirhead, cp, len); 77151898Smckusick dirplen = len; 77251898Smckusick } else { 77353150Smckusick getexp_err(ep, tgrp); 77451898Smckusick goto nextline; 77551898Smckusick } 77651898Smckusick *endcp = savedc; 77751898Smckusick } else { 77851898Smckusick savedc = *endcp; 77951898Smckusick *endcp = '\0'; 78051898Smckusick got_nondir = 1; 78166163Spendry if (ep == (struct exportlist *)NULL) { 78253150Smckusick getexp_err(ep, tgrp); 78351898Smckusick goto nextline; 78451898Smckusick } 78553150Smckusick 78653150Smckusick /* 78753150Smckusick * Get the host or netgroup. 78853150Smckusick */ 78953150Smckusick setnetgrent(cp); 79053150Smckusick netgrp = getnetgrent(&hst, &usr, &dom); 79153150Smckusick do { 79253150Smckusick if (has_host) { 79353150Smckusick grp->gr_next = get_grp(); 79453150Smckusick grp = grp->gr_next; 79553150Smckusick } 79653150Smckusick if (netgrp) { 79753150Smckusick if (get_host(hst, grp)) { 79853150Smckusick syslog(LOG_ERR, "Bad netgroup %s", cp); 79953150Smckusick getexp_err(ep, tgrp); 80068095Shibler endnetgrent(); 80153150Smckusick goto nextline; 80253150Smckusick } 80353150Smckusick } else if (get_host(cp, grp)) { 80453150Smckusick getexp_err(ep, tgrp); 80553150Smckusick goto nextline; 80653150Smckusick } 80753150Smckusick has_host = TRUE; 80853150Smckusick } while (netgrp && getnetgrent(&hst, &usr, &dom)); 80953150Smckusick endnetgrent(); 81051898Smckusick *endcp = savedc; 81138460Smckusick } 81238460Smckusick cp = endcp; 81338460Smckusick nextfield(&cp, &endcp); 81445271Smckusick len = endcp - cp; 81538460Smckusick } 81651898Smckusick if (check_options(dirhead)) { 81753150Smckusick getexp_err(ep, tgrp); 81851898Smckusick goto nextline; 81951898Smckusick } 82051898Smckusick if (!has_host) { 82151898Smckusick grp->gr_type = GT_HOST; 82251667Smckusick if (debug) 82351667Smckusick fprintf(stderr,"Adding a default entry\n"); 82451667Smckusick /* add a default group and make the grp list NULL */ 82551667Smckusick hpe = (struct hostent *)malloc(sizeof(struct hostent)); 82666163Spendry if (hpe == (struct hostent *)NULL) 82751898Smckusick out_of_mem(); 82851898Smckusick hpe->h_name = "Default"; 82951667Smckusick hpe->h_addrtype = AF_INET; 83051667Smckusick hpe->h_length = sizeof (u_long); 83166163Spendry hpe->h_addr_list = (char **)NULL; 83251898Smckusick grp->gr_ptr.gt_hostent = hpe; 83353150Smckusick 83453150Smckusick /* 83553150Smckusick * Don't allow a network export coincide with a list of 83653150Smckusick * host(s) on the same line. 83753150Smckusick */ 83853150Smckusick } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 83953150Smckusick getexp_err(ep, tgrp); 84053150Smckusick goto nextline; 84151667Smckusick } 84253150Smckusick 84353150Smckusick /* 84453150Smckusick * Loop through hosts, pushing the exports into the kernel. 84553150Smckusick * After loop, tgrp points to the start of the list and 84653150Smckusick * grp points to the last entry in the list. 84753150Smckusick */ 84853150Smckusick grp = tgrp; 84953150Smckusick do { 85053150Smckusick if (do_mount(ep, grp, exflags, &anon, dirp, 85151898Smckusick dirplen, &fsb)) { 85253150Smckusick getexp_err(ep, tgrp); 85351898Smckusick goto nextline; 85453150Smckusick } 85553150Smckusick } while (grp->gr_next && (grp = grp->gr_next)); 85651898Smckusick 85751898Smckusick /* 85851898Smckusick * Success. Update the data structures. 85951898Smckusick */ 86051898Smckusick if (has_host) { 86168645Smckusick hang_dirp(dirhead, tgrp, ep, opt_flags); 86251898Smckusick grp->gr_next = grphead; 86353150Smckusick grphead = tgrp; 86451898Smckusick } else { 86566163Spendry hang_dirp(dirhead, (struct grouplist *)NULL, ep, 86668645Smckusick opt_flags); 86751898Smckusick free_grp(grp); 86851898Smckusick } 86966163Spendry dirhead = (struct dirlist *)NULL; 87051898Smckusick if ((ep->ex_flag & EX_LINKED) == 0) { 87151898Smckusick ep2 = exphead; 87251898Smckusick epp = &exphead; 87351898Smckusick 87451898Smckusick /* 87551898Smckusick * Insert in the list in alphabetical order. 87651898Smckusick */ 87751898Smckusick while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 87851898Smckusick epp = &ep2->ex_next; 87951898Smckusick ep2 = ep2->ex_next; 88051898Smckusick } 88151898Smckusick if (ep2) 88251898Smckusick ep->ex_next = ep2; 88351898Smckusick *epp = ep; 88451898Smckusick ep->ex_flag |= EX_LINKED; 88551898Smckusick } 88651898Smckusick nextline: 88751898Smckusick if (dirhead) { 88851898Smckusick free_dir(dirhead); 88966163Spendry dirhead = (struct dirlist *)NULL; 89051898Smckusick } 89151898Smckusick } 89251898Smckusick fclose(exp_file); 89351898Smckusick } 89451898Smckusick 89551898Smckusick /* 89651898Smckusick * Allocate an export list element 89751898Smckusick */ 89851898Smckusick struct exportlist * 89951898Smckusick get_exp() 90051898Smckusick { 90166163Spendry struct exportlist *ep; 90251898Smckusick 90351898Smckusick ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 90466163Spendry if (ep == (struct exportlist *)NULL) 90551898Smckusick out_of_mem(); 906*68996Sbostic memset(ep, 0, sizeof(struct exportlist)); 90751898Smckusick return (ep); 90851898Smckusick } 90951898Smckusick 91051898Smckusick /* 91151898Smckusick * Allocate a group list element 91251898Smckusick */ 91351898Smckusick struct grouplist * 91451898Smckusick get_grp() 91551898Smckusick { 91666163Spendry struct grouplist *gp; 91751898Smckusick 91851898Smckusick gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 91966163Spendry if (gp == (struct grouplist *)NULL) 92051898Smckusick out_of_mem(); 921*68996Sbostic memset(gp, 0, sizeof(struct grouplist)); 92251898Smckusick return (gp); 92351898Smckusick } 92451898Smckusick 92551898Smckusick /* 92651898Smckusick * Clean up upon an error in get_exportlist(). 92751898Smckusick */ 92851898Smckusick void 92951898Smckusick getexp_err(ep, grp) 93051898Smckusick struct exportlist *ep; 93151898Smckusick struct grouplist *grp; 93251898Smckusick { 93353150Smckusick struct grouplist *tgrp; 93451898Smckusick 93551898Smckusick syslog(LOG_ERR, "Bad exports list line %s", line); 93659017Smckusick if (ep && (ep->ex_flag & EX_LINKED) == 0) 93751898Smckusick free_exp(ep); 93853150Smckusick while (grp) { 93953150Smckusick tgrp = grp; 94053150Smckusick grp = grp->gr_next; 94153150Smckusick free_grp(tgrp); 94253150Smckusick } 94351898Smckusick } 94451898Smckusick 94551898Smckusick /* 94651898Smckusick * Search the export list for a matching fs. 94751898Smckusick */ 94851898Smckusick struct exportlist * 94951898Smckusick ex_search(fsid) 95052109Smckusick fsid_t *fsid; 95151898Smckusick { 95266163Spendry struct exportlist *ep; 95351898Smckusick 95451898Smckusick ep = exphead; 95551898Smckusick while (ep) { 95651898Smckusick if (ep->ex_fs.val[0] == fsid->val[0] && 95751898Smckusick ep->ex_fs.val[1] == fsid->val[1]) 95851898Smckusick return (ep); 95951898Smckusick ep = ep->ex_next; 96051898Smckusick } 96151898Smckusick return (ep); 96251898Smckusick } 96351898Smckusick 96451898Smckusick /* 96551898Smckusick * Add a directory path to the list. 96651898Smckusick */ 96751898Smckusick char * 96851898Smckusick add_expdir(dpp, cp, len) 96951898Smckusick struct dirlist **dpp; 97051898Smckusick char *cp; 97151898Smckusick int len; 97251898Smckusick { 97366163Spendry struct dirlist *dp; 97451898Smckusick 97551898Smckusick dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 97651898Smckusick dp->dp_left = *dpp; 97766163Spendry dp->dp_right = (struct dirlist *)NULL; 97851898Smckusick dp->dp_flag = 0; 97966163Spendry dp->dp_hosts = (struct hostlist *)NULL; 98051898Smckusick strcpy(dp->dp_dirp, cp); 98151898Smckusick *dpp = dp; 98251898Smckusick return (dp->dp_dirp); 98351898Smckusick } 98451898Smckusick 98551898Smckusick /* 98651898Smckusick * Hang the dir list element off the dirpath binary tree as required 98751898Smckusick * and update the entry for host. 98851898Smckusick */ 98951898Smckusick void 99068645Smckusick hang_dirp(dp, grp, ep, flags) 99166163Spendry struct dirlist *dp; 99251898Smckusick struct grouplist *grp; 99351898Smckusick struct exportlist *ep; 99468645Smckusick int flags; 99551898Smckusick { 99666163Spendry struct hostlist *hp; 99751898Smckusick struct dirlist *dp2; 99851898Smckusick 99968645Smckusick if (flags & OP_ALLDIRS) { 100051898Smckusick if (ep->ex_defdir) 100151898Smckusick free((caddr_t)dp); 100251898Smckusick else 100351898Smckusick ep->ex_defdir = dp; 100468645Smckusick if (grp == (struct grouplist *)NULL) { 100555292Smckusick ep->ex_defdir->dp_flag |= DP_DEFSET; 100668645Smckusick if (flags & OP_KERB) 100768645Smckusick ep->ex_defdir->dp_flag |= DP_KERB; 100868645Smckusick } else while (grp) { 100951898Smckusick hp = get_ht(); 101068645Smckusick if (flags & OP_KERB) 101168645Smckusick hp->ht_flag |= DP_KERB; 101251898Smckusick hp->ht_grp = grp; 101351898Smckusick hp->ht_next = ep->ex_defdir->dp_hosts; 101451898Smckusick ep->ex_defdir->dp_hosts = hp; 101555292Smckusick grp = grp->gr_next; 101655292Smckusick } 101751898Smckusick } else { 101853150Smckusick 101953150Smckusick /* 102053150Smckusick * Loop throught the directories adding them to the tree. 102153150Smckusick */ 102251898Smckusick while (dp) { 102351898Smckusick dp2 = dp->dp_left; 102468645Smckusick add_dlist(&ep->ex_dirl, dp, grp, flags); 102551898Smckusick dp = dp2; 102651898Smckusick } 102751898Smckusick } 102851898Smckusick } 102951898Smckusick 103051898Smckusick /* 103151898Smckusick * Traverse the binary tree either updating a node that is already there 103251898Smckusick * for the new directory or adding the new node. 103351898Smckusick */ 103451898Smckusick void 103568645Smckusick add_dlist(dpp, newdp, grp, flags) 103651898Smckusick struct dirlist **dpp; 103751898Smckusick struct dirlist *newdp; 103866163Spendry struct grouplist *grp; 103968645Smckusick int flags; 104051898Smckusick { 104166163Spendry struct dirlist *dp; 104266163Spendry struct hostlist *hp; 104351898Smckusick int cmp; 104451898Smckusick 104551898Smckusick dp = *dpp; 104651898Smckusick if (dp) { 104751898Smckusick cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 104851898Smckusick if (cmp > 0) { 104968645Smckusick add_dlist(&dp->dp_left, newdp, grp, flags); 105051898Smckusick return; 105151898Smckusick } else if (cmp < 0) { 105268645Smckusick add_dlist(&dp->dp_right, newdp, grp, flags); 105351898Smckusick return; 105451898Smckusick } else 105551898Smckusick free((caddr_t)newdp); 105651898Smckusick } else { 105751898Smckusick dp = newdp; 105866163Spendry dp->dp_left = (struct dirlist *)NULL; 105951898Smckusick *dpp = dp; 106051898Smckusick } 106153150Smckusick if (grp) { 106253150Smckusick 106353150Smckusick /* 106453150Smckusick * Hang all of the host(s) off of the directory point. 106553150Smckusick */ 106653150Smckusick do { 106753150Smckusick hp = get_ht(); 106868645Smckusick if (flags & OP_KERB) 106968645Smckusick hp->ht_flag |= DP_KERB; 107053150Smckusick hp->ht_grp = grp; 107153150Smckusick hp->ht_next = dp->dp_hosts; 107253150Smckusick dp->dp_hosts = hp; 107353150Smckusick grp = grp->gr_next; 107453150Smckusick } while (grp); 107568645Smckusick } else { 107651898Smckusick dp->dp_flag |= DP_DEFSET; 107768645Smckusick if (flags & OP_KERB) 107868645Smckusick dp->dp_flag |= DP_KERB; 107968645Smckusick } 108051898Smckusick } 108151898Smckusick 108251898Smckusick /* 108351898Smckusick * Search for a dirpath on the export point. 108451898Smckusick */ 108551898Smckusick struct dirlist * 108651898Smckusick dirp_search(dp, dirpath) 108766163Spendry struct dirlist *dp; 108851898Smckusick char *dirpath; 108951898Smckusick { 109066163Spendry int cmp; 109151898Smckusick 109251898Smckusick if (dp) { 109351898Smckusick cmp = strcmp(dp->dp_dirp, dirpath); 109451898Smckusick if (cmp > 0) 109551898Smckusick return (dirp_search(dp->dp_left, dirpath)); 109651898Smckusick else if (cmp < 0) 109751898Smckusick return (dirp_search(dp->dp_right, dirpath)); 109851898Smckusick else 109951898Smckusick return (dp); 110051898Smckusick } 110151898Smckusick return (dp); 110251898Smckusick } 110351898Smckusick 110451898Smckusick /* 110551898Smckusick * Scan for a host match in a directory tree. 110651898Smckusick */ 110766163Spendry int 110868645Smckusick chk_host(dp, saddr, defsetp, hostsetp) 110951898Smckusick struct dirlist *dp; 111051898Smckusick u_long saddr; 111151898Smckusick int *defsetp; 111268645Smckusick int *hostsetp; 111351898Smckusick { 111466163Spendry struct hostlist *hp; 111566163Spendry struct grouplist *grp; 111666163Spendry u_long **addrp; 111751898Smckusick 111851898Smckusick if (dp) { 111951898Smckusick if (dp->dp_flag & DP_DEFSET) 112068645Smckusick *defsetp = dp->dp_flag; 112151898Smckusick hp = dp->dp_hosts; 112251898Smckusick while (hp) { 112351898Smckusick grp = hp->ht_grp; 112451898Smckusick switch (grp->gr_type) { 112551898Smckusick case GT_HOST: 112651898Smckusick addrp = (u_long **) 112751898Smckusick grp->gr_ptr.gt_hostent->h_addr_list; 112851898Smckusick while (*addrp) { 112968645Smckusick if (**addrp == saddr) { 113068645Smckusick *hostsetp = (hp->ht_flag | DP_HOSTSET); 113151898Smckusick return (1); 113268645Smckusick } 113351898Smckusick addrp++; 113451898Smckusick } 113551898Smckusick break; 113651898Smckusick case GT_NET: 113751898Smckusick if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 113868645Smckusick grp->gr_ptr.gt_net.nt_net) { 113968645Smckusick *hostsetp = (hp->ht_flag | DP_HOSTSET); 114051898Smckusick return (1); 114168645Smckusick } 114251898Smckusick break; 114351898Smckusick }; 114451898Smckusick hp = hp->ht_next; 114551898Smckusick } 114651898Smckusick } 114751898Smckusick return (0); 114851898Smckusick } 114951898Smckusick 115051898Smckusick /* 115151898Smckusick * Scan tree for a host that matches the address. 115251898Smckusick */ 115366163Spendry int 115451898Smckusick scan_tree(dp, saddr) 115566163Spendry struct dirlist *dp; 115651898Smckusick u_long saddr; 115751898Smckusick { 115868645Smckusick int defset, hostset; 115951898Smckusick 116051898Smckusick if (dp) { 116151898Smckusick if (scan_tree(dp->dp_left, saddr)) 116251898Smckusick return (1); 116368645Smckusick if (chk_host(dp, saddr, &defset, &hostset)) 116451898Smckusick return (1); 116551898Smckusick if (scan_tree(dp->dp_right, saddr)) 116651898Smckusick return (1); 116751898Smckusick } 116851898Smckusick return (0); 116951898Smckusick } 117051898Smckusick 117151898Smckusick /* 117251898Smckusick * Traverse the dirlist tree and free it up. 117351898Smckusick */ 117451898Smckusick void 117551898Smckusick free_dir(dp) 117666163Spendry struct dirlist *dp; 117751898Smckusick { 117851898Smckusick 117951898Smckusick if (dp) { 118051898Smckusick free_dir(dp->dp_left); 118151898Smckusick free_dir(dp->dp_right); 118251898Smckusick free_host(dp->dp_hosts); 118351898Smckusick free((caddr_t)dp); 118451898Smckusick } 118551898Smckusick } 118651898Smckusick 118751898Smckusick /* 118851898Smckusick * Parse the option string and update fields. 118951898Smckusick * Option arguments may either be -<option>=<value> or 119051898Smckusick * -<option> <value> 119151898Smckusick */ 119266163Spendry int 119351898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 119451898Smckusick char **cpp, **endcpp; 119551898Smckusick struct exportlist *ep; 119651898Smckusick struct grouplist *grp; 119751898Smckusick int *has_hostp; 119851898Smckusick int *exflagsp; 119951898Smckusick struct ucred *cr; 120051898Smckusick { 120166163Spendry char *cpoptarg, *cpoptend; 120251898Smckusick char *cp, *endcp, *cpopt, savedc, savedc2; 120351898Smckusick int allflag, usedarg; 120451898Smckusick 120551898Smckusick cpopt = *cpp; 120651898Smckusick cpopt++; 120751898Smckusick cp = *endcpp; 120851898Smckusick savedc = *cp; 120951898Smckusick *cp = '\0'; 121051898Smckusick while (cpopt && *cpopt) { 121151898Smckusick allflag = 1; 121251898Smckusick usedarg = -2; 1213*68996Sbostic if (cpoptend = strchr(cpopt, ',')) { 121451898Smckusick *cpoptend++ = '\0'; 1215*68996Sbostic if (cpoptarg = strchr(cpopt, '=')) 121651898Smckusick *cpoptarg++ = '\0'; 121751898Smckusick } else { 1218*68996Sbostic if (cpoptarg = strchr(cpopt, '=')) 121951898Smckusick *cpoptarg++ = '\0'; 122051898Smckusick else { 122151898Smckusick *cp = savedc; 122251898Smckusick nextfield(&cp, &endcp); 122351898Smckusick **endcpp = '\0'; 122451898Smckusick if (endcp > cp && *cp != '-') { 122551898Smckusick cpoptarg = cp; 122651898Smckusick savedc2 = *endcp; 122751898Smckusick *endcp = '\0'; 122851898Smckusick usedarg = 0; 122951667Smckusick } 123051667Smckusick } 123151667Smckusick } 123251898Smckusick if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 123351898Smckusick *exflagsp |= MNT_EXRDONLY; 123451898Smckusick } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 123551898Smckusick !(allflag = strcmp(cpopt, "mapall")) || 123651898Smckusick !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 123751898Smckusick usedarg++; 123851898Smckusick parsecred(cpoptarg, cr); 123951898Smckusick if (allflag == 0) { 124051898Smckusick *exflagsp |= MNT_EXPORTANON; 124151898Smckusick opt_flags |= OP_MAPALL; 124251898Smckusick } else 124351898Smckusick opt_flags |= OP_MAPROOT; 124451898Smckusick } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 124551898Smckusick *exflagsp |= MNT_EXKERB; 124651898Smckusick opt_flags |= OP_KERB; 124753150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "mask") || 124853150Smckusick !strcmp(cpopt, "m"))) { 124951898Smckusick if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 125051898Smckusick syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 125151898Smckusick return (1); 125251898Smckusick } 125351898Smckusick usedarg++; 125451898Smckusick opt_flags |= OP_MASK; 125553150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "network") || 125653150Smckusick !strcmp(cpopt, "n"))) { 125751898Smckusick if (grp->gr_type != GT_NULL) { 125851898Smckusick syslog(LOG_ERR, "Network/host conflict"); 125951898Smckusick return (1); 126051898Smckusick } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 126151898Smckusick syslog(LOG_ERR, "Bad net: %s", cpoptarg); 126251898Smckusick return (1); 126351898Smckusick } 126451898Smckusick grp->gr_type = GT_NET; 126551898Smckusick *has_hostp = 1; 126651898Smckusick usedarg++; 126751898Smckusick opt_flags |= OP_NET; 126851898Smckusick } else if (!strcmp(cpopt, "alldirs")) { 126951898Smckusick opt_flags |= OP_ALLDIRS; 127051898Smckusick #ifdef ISO 127151898Smckusick } else if (cpoptarg && !strcmp(cpopt, "iso")) { 127251898Smckusick if (get_isoaddr(cpoptarg, grp)) { 127351898Smckusick syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 127451898Smckusick return (1); 127551898Smckusick } 127651898Smckusick *has_hostp = 1; 127751898Smckusick usedarg++; 127851898Smckusick opt_flags |= OP_ISO; 127951898Smckusick #endif /* ISO */ 128051898Smckusick } else { 128151898Smckusick syslog(LOG_ERR, "Bad opt %s", cpopt); 128251898Smckusick return (1); 128351667Smckusick } 128451898Smckusick if (usedarg >= 0) { 128551898Smckusick *endcp = savedc2; 128651898Smckusick **endcpp = savedc; 128751898Smckusick if (usedarg > 0) { 128851898Smckusick *cpp = cp; 128951898Smckusick *endcpp = endcp; 129051898Smckusick } 129151898Smckusick return (0); 129251898Smckusick } 129351898Smckusick cpopt = cpoptend; 129451667Smckusick } 129551898Smckusick **endcpp = savedc; 129651898Smckusick return (0); 129751898Smckusick } 129851898Smckusick 129951898Smckusick /* 130051898Smckusick * Translate a character string to the corresponding list of network 130151898Smckusick * addresses for a hostname. 130251898Smckusick */ 130366163Spendry int 130451898Smckusick get_host(cp, grp) 130551898Smckusick char *cp; 130666163Spendry struct grouplist *grp; 130751898Smckusick { 130866163Spendry struct hostent *hp, *nhp; 130966163Spendry char **addrp, **naddrp; 131051898Smckusick struct hostent t_host; 131151898Smckusick int i; 131251898Smckusick u_long saddr; 131351898Smckusick char *aptr[2]; 131451898Smckusick 131551898Smckusick if (grp->gr_type != GT_NULL) 131651898Smckusick return (1); 131751898Smckusick if ((hp = gethostbyname(cp)) == NULL) { 131851898Smckusick if (isdigit(*cp)) { 131951898Smckusick saddr = inet_addr(cp); 132051898Smckusick if (saddr == -1) { 132168095Shibler syslog(LOG_ERR, "Inet_addr failed for %s", cp); 132251898Smckusick return (1); 132351898Smckusick } 132451898Smckusick if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 132551898Smckusick AF_INET)) == NULL) { 132651898Smckusick hp = &t_host; 132751898Smckusick hp->h_name = cp; 132851898Smckusick hp->h_addrtype = AF_INET; 132951898Smckusick hp->h_length = sizeof (u_long); 133051898Smckusick hp->h_addr_list = aptr; 133151898Smckusick aptr[0] = (char *)&saddr; 133266163Spendry aptr[1] = (char *)NULL; 133351898Smckusick } 133451898Smckusick } else { 133568095Shibler syslog(LOG_ERR, "Gethostbyname failed for %s", cp); 133651898Smckusick return (1); 133751898Smckusick } 133851898Smckusick } 133951898Smckusick grp->gr_type = GT_HOST; 134051898Smckusick nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 134151898Smckusick malloc(sizeof(struct hostent)); 134266163Spendry if (nhp == (struct hostent *)NULL) 134351898Smckusick out_of_mem(); 1344*68996Sbostic memmove(nhp, hp, sizeof(struct hostent)); 134551898Smckusick i = strlen(hp->h_name)+1; 134651898Smckusick nhp->h_name = (char *)malloc(i); 134766163Spendry if (nhp->h_name == (char *)NULL) 134851898Smckusick out_of_mem(); 1349*68996Sbostic memmove(nhp->h_name, hp->h_name, i); 135051898Smckusick addrp = hp->h_addr_list; 135151898Smckusick i = 1; 135251898Smckusick while (*addrp++) 135351898Smckusick i++; 135451898Smckusick naddrp = nhp->h_addr_list = (char **) 135551898Smckusick malloc(i*sizeof(char *)); 135666163Spendry if (naddrp == (char **)NULL) 135751898Smckusick out_of_mem(); 135851898Smckusick addrp = hp->h_addr_list; 135951898Smckusick while (*addrp) { 136051898Smckusick *naddrp = (char *) 136151898Smckusick malloc(hp->h_length); 136266163Spendry if (*naddrp == (char *)NULL) 136351898Smckusick out_of_mem(); 1364*68996Sbostic memmove(*naddrp, *addrp, hp->h_length); 136551898Smckusick addrp++; 136651898Smckusick naddrp++; 136751898Smckusick } 136866163Spendry *naddrp = (char *)NULL; 136953150Smckusick if (debug) 137053150Smckusick fprintf(stderr, "got host %s\n", hp->h_name); 137151898Smckusick return (0); 137251898Smckusick } 137351898Smckusick 137451898Smckusick /* 137551898Smckusick * Free up an exports list component 137651898Smckusick */ 137751898Smckusick void 137851898Smckusick free_exp(ep) 137966163Spendry struct exportlist *ep; 138051898Smckusick { 138151898Smckusick 138251898Smckusick if (ep->ex_defdir) { 138351898Smckusick free_host(ep->ex_defdir->dp_hosts); 138451898Smckusick free((caddr_t)ep->ex_defdir); 138551898Smckusick } 138651898Smckusick if (ep->ex_fsdir) 138751898Smckusick free(ep->ex_fsdir); 138851898Smckusick free_dir(ep->ex_dirl); 138951898Smckusick free((caddr_t)ep); 139051898Smckusick } 139151898Smckusick 139251898Smckusick /* 139351898Smckusick * Free hosts. 139451898Smckusick */ 139551898Smckusick void 139651898Smckusick free_host(hp) 139766163Spendry struct hostlist *hp; 139851898Smckusick { 139966163Spendry struct hostlist *hp2; 140051898Smckusick 140151898Smckusick while (hp) { 140251898Smckusick hp2 = hp; 140351898Smckusick hp = hp->ht_next; 140451898Smckusick free((caddr_t)hp2); 140551898Smckusick } 140651898Smckusick } 140751898Smckusick 140851898Smckusick struct hostlist * 140951898Smckusick get_ht() 141051898Smckusick { 141166163Spendry struct hostlist *hp; 141251898Smckusick 141351898Smckusick hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 141466163Spendry if (hp == (struct hostlist *)NULL) 141551898Smckusick out_of_mem(); 141666163Spendry hp->ht_next = (struct hostlist *)NULL; 141768645Smckusick hp->ht_flag = 0; 141851898Smckusick return (hp); 141951898Smckusick } 142051898Smckusick 142151898Smckusick #ifdef ISO 142251898Smckusick /* 142351898Smckusick * Translate an iso address. 142451898Smckusick */ 142551898Smckusick get_isoaddr(cp, grp) 142651898Smckusick char *cp; 142751898Smckusick struct grouplist *grp; 142851898Smckusick { 142951898Smckusick struct iso_addr *isop; 143051898Smckusick struct sockaddr_iso *isoaddr; 143151898Smckusick 143251898Smckusick if (grp->gr_type != GT_NULL) 143351898Smckusick return (1); 143451898Smckusick if ((isop = iso_addr(cp)) == NULL) { 143551898Smckusick syslog(LOG_ERR, 143651898Smckusick "iso_addr failed, ignored"); 143751898Smckusick return (1); 143851898Smckusick } 143951898Smckusick isoaddr = (struct sockaddr_iso *) 144051898Smckusick malloc(sizeof (struct sockaddr_iso)); 144166163Spendry if (isoaddr == (struct sockaddr_iso *)NULL) 144251898Smckusick out_of_mem(); 1443*68996Sbostic memset(isoaddr, 0, sizeof(struct sockaddr_iso)); 1444*68996Sbostic memmove(&isoaddr->siso_addr, isop, sizeof(struct iso_addr)); 1445*68996Sbostic isoaddr->siso_len = sizeof(struct sockaddr_iso); 144651898Smckusick isoaddr->siso_family = AF_ISO; 144751898Smckusick grp->gr_type = GT_ISO; 144851898Smckusick grp->gr_ptr.gt_isoaddr = isoaddr; 144951898Smckusick return (0); 145051898Smckusick } 145151898Smckusick #endif /* ISO */ 145251898Smckusick 145351898Smckusick /* 145451898Smckusick * Out of memory, fatal 145551898Smckusick */ 145651898Smckusick void 145751898Smckusick out_of_mem() 145851898Smckusick { 145951898Smckusick 146051898Smckusick syslog(LOG_ERR, "Out of memory"); 146151667Smckusick exit(2); 146251667Smckusick } 146351667Smckusick 146451898Smckusick /* 146551898Smckusick * Do the mount syscall with the update flag to push the export info into 146651898Smckusick * the kernel. 146751898Smckusick */ 146866163Spendry int 146951898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 147051667Smckusick struct exportlist *ep; 147151667Smckusick struct grouplist *grp; 147251898Smckusick int exflags; 147351667Smckusick struct ucred *anoncrp; 147451898Smckusick char *dirp; 147551898Smckusick int dirplen; 147651898Smckusick struct statfs *fsb; 147751667Smckusick { 147866163Spendry char *cp = (char *)NULL; 147966163Spendry u_long **addrp; 148051898Smckusick int done; 148166163Spendry char savedc = '\0'; 148251898Smckusick struct sockaddr_in sin, imask; 148365713Shibler union { 148465713Shibler struct ufs_args ua; 148565713Shibler struct iso_args ia; 148665713Shibler struct mfs_args ma; 148765713Shibler } args; 148851898Smckusick u_long net; 148951667Smckusick 149065713Shibler args.ua.fspec = 0; 149165713Shibler args.ua.export.ex_flags = exflags; 149265713Shibler args.ua.export.ex_anon = *anoncrp; 1493*68996Sbostic memset(&sin, 0, sizeof(sin)); 1494*68996Sbostic memset(&imask, 0, sizeof(imask)); 149551667Smckusick sin.sin_family = AF_INET; 149651667Smckusick sin.sin_len = sizeof(sin); 149751898Smckusick imask.sin_family = AF_INET; 149851898Smckusick imask.sin_len = sizeof(sin); 149951898Smckusick if (grp->gr_type == GT_HOST) 150051667Smckusick addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 150151898Smckusick else 150266163Spendry addrp = (u_long **)NULL; 150351667Smckusick done = FALSE; 150451898Smckusick while (!done) { 150551898Smckusick switch (grp->gr_type) { 150651898Smckusick case GT_HOST: 150764903Smckusick if (addrp) { 150851712Smckusick sin.sin_addr.s_addr = **addrp; 150965713Shibler args.ua.export.ex_addrlen = sizeof(sin); 151064903Smckusick } else 151165713Shibler args.ua.export.ex_addrlen = 0; 151265713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 151365713Shibler args.ua.export.ex_masklen = 0; 151451898Smckusick break; 151551898Smckusick case GT_NET: 151651898Smckusick if (grp->gr_ptr.gt_net.nt_mask) 151751898Smckusick imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 151851898Smckusick else { 151951898Smckusick net = ntohl(grp->gr_ptr.gt_net.nt_net); 152051898Smckusick if (IN_CLASSA(net)) 152151898Smckusick imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 152251898Smckusick else if (IN_CLASSB(net)) 152351898Smckusick imask.sin_addr.s_addr = 152451898Smckusick inet_addr("255.255.0.0"); 152551898Smckusick else 152651898Smckusick imask.sin_addr.s_addr = 152751898Smckusick inet_addr("255.255.255.0"); 152851898Smckusick grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 152951898Smckusick } 153051898Smckusick sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 153165713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 153265713Shibler args.ua.export.ex_addrlen = sizeof (sin); 153365713Shibler args.ua.export.ex_mask = (struct sockaddr *)&imask; 153465713Shibler args.ua.export.ex_masklen = sizeof (imask); 153551898Smckusick break; 153651667Smckusick #ifdef ISO 153751898Smckusick case GT_ISO: 153865713Shibler args.ua.export.ex_addr = 153965713Shibler (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 154065713Shibler args.ua.export.ex_addrlen = 154165713Shibler sizeof(struct sockaddr_iso); 154265713Shibler args.ua.export.ex_masklen = 0; 154351898Smckusick break; 154451667Smckusick #endif /* ISO */ 154551898Smckusick default: 154651667Smckusick syslog(LOG_ERR, "Bad grouptype"); 154751898Smckusick if (cp) 154851898Smckusick *cp = savedc; 154951898Smckusick return (1); 155051898Smckusick }; 155152109Smckusick 155252109Smckusick /* 155352109Smckusick * XXX: 155452109Smckusick * Maybe I should just use the fsb->f_mntonname path instead 155552109Smckusick * of looping back up the dirp to the mount point?? 155652109Smckusick * Also, needs to know how to export all types of local 155768645Smckusick * exportable file systems and not just "ufs". 155852109Smckusick */ 155968645Smckusick while (mount(fsb->f_fstypename, dirp, 156052109Smckusick fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 156151898Smckusick if (cp) 156251898Smckusick *cp-- = savedc; 156351898Smckusick else 156451898Smckusick cp = dirp + dirplen - 1; 156551667Smckusick if (errno == EPERM) { 156651667Smckusick syslog(LOG_ERR, 156751898Smckusick "Can't change attributes for %s.\n", dirp); 156851898Smckusick return (1); 156951667Smckusick } 157051898Smckusick if (opt_flags & OP_ALLDIRS) { 157151898Smckusick syslog(LOG_ERR, "Not root dir"); 157251898Smckusick return (1); 157351898Smckusick } 157451667Smckusick /* back up over the last component */ 157551898Smckusick while (*cp == '/' && cp > dirp) 157651667Smckusick cp--; 157751898Smckusick while (*(cp - 1) != '/' && cp > dirp) 157851667Smckusick cp--; 157951898Smckusick if (cp == dirp) { 158051898Smckusick if (debug) 158151667Smckusick fprintf(stderr,"mnt unsucc\n"); 158251898Smckusick syslog(LOG_ERR, "Can't export %s", dirp); 158351898Smckusick return (1); 158451667Smckusick } 158551667Smckusick savedc = *cp; 158651667Smckusick *cp = '\0'; 158751667Smckusick } 158851898Smckusick if (addrp) { 158951667Smckusick ++addrp; 159066163Spendry if (*addrp == (u_long *)NULL) 159151667Smckusick done = TRUE; 159251898Smckusick } else 159351898Smckusick done = TRUE; 159451898Smckusick } 159551898Smckusick if (cp) 159651898Smckusick *cp = savedc; 159751898Smckusick return (0); 159851898Smckusick } 159951898Smckusick 160051898Smckusick /* 160151898Smckusick * Translate a net address. 160251898Smckusick */ 160366163Spendry int 160451898Smckusick get_net(cp, net, maskflg) 160551898Smckusick char *cp; 160651898Smckusick struct netmsk *net; 160751898Smckusick int maskflg; 160851898Smckusick { 160966163Spendry struct netent *np; 161066163Spendry long netaddr; 161151898Smckusick struct in_addr inetaddr, inetaddr2; 161251898Smckusick char *name; 161351898Smckusick 161451898Smckusick if (np = getnetbyname(cp)) 161551898Smckusick inetaddr = inet_makeaddr(np->n_net, 0); 161651898Smckusick else if (isdigit(*cp)) { 161751898Smckusick if ((netaddr = inet_network(cp)) == -1) 161851898Smckusick return (1); 161951898Smckusick inetaddr = inet_makeaddr(netaddr, 0); 162051898Smckusick /* 162151898Smckusick * Due to arbritrary subnet masks, you don't know how many 162251898Smckusick * bits to shift the address to make it into a network, 162351898Smckusick * however you do know how to make a network address into 162451898Smckusick * a host with host == 0 and then compare them. 162551898Smckusick * (What a pest) 162651898Smckusick */ 162751898Smckusick if (!maskflg) { 162851898Smckusick setnetent(0); 162951898Smckusick while (np = getnetent()) { 163051898Smckusick inetaddr2 = inet_makeaddr(np->n_net, 0); 163151898Smckusick if (inetaddr2.s_addr == inetaddr.s_addr) 163251898Smckusick break; 163351898Smckusick } 163451898Smckusick endnetent(); 163551667Smckusick } 163651898Smckusick } else 163751898Smckusick return (1); 163851898Smckusick if (maskflg) 163951898Smckusick net->nt_mask = inetaddr.s_addr; 164051898Smckusick else { 164151898Smckusick if (np) 164251898Smckusick name = np->n_name; 164351898Smckusick else 164451898Smckusick name = inet_ntoa(inetaddr); 164551898Smckusick net->nt_name = (char *)malloc(strlen(name) + 1); 164666163Spendry if (net->nt_name == (char *)NULL) 164751898Smckusick out_of_mem(); 164851898Smckusick strcpy(net->nt_name, name); 164951898Smckusick net->nt_net = inetaddr.s_addr; 165038460Smckusick } 165151898Smckusick return (0); 165238460Smckusick } 165338460Smckusick 165438460Smckusick /* 165538460Smckusick * Parse out the next white space separated field 165638460Smckusick */ 165751667Smckusick void 165838460Smckusick nextfield(cp, endcp) 165938460Smckusick char **cp; 166038460Smckusick char **endcp; 166138460Smckusick { 166266163Spendry char *p; 166338460Smckusick 166438460Smckusick p = *cp; 166538460Smckusick while (*p == ' ' || *p == '\t') 166638460Smckusick p++; 166751898Smckusick if (*p == '\n' || *p == '\0') 166838460Smckusick *cp = *endcp = p; 166951898Smckusick else { 167051898Smckusick *cp = p++; 167151898Smckusick while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 167251898Smckusick p++; 167351898Smckusick *endcp = p; 167438460Smckusick } 167538460Smckusick } 167639681Smckusick 167739681Smckusick /* 167851898Smckusick * Get an exports file line. Skip over blank lines and handle line 167951898Smckusick * continuations. 168039681Smckusick */ 168166163Spendry int 168251898Smckusick get_line() 168339681Smckusick { 168466163Spendry char *p, *cp; 168566163Spendry int len; 168651898Smckusick int totlen, cont_line; 168739681Smckusick 168851898Smckusick /* 168951898Smckusick * Loop around ignoring blank lines and getting all continuation lines. 169051898Smckusick */ 169151898Smckusick p = line; 169251898Smckusick totlen = 0; 169351898Smckusick do { 169451898Smckusick if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 169551898Smckusick return (0); 169651898Smckusick len = strlen(p); 169751898Smckusick cp = p + len - 1; 169851898Smckusick cont_line = 0; 169951898Smckusick while (cp >= p && 170051898Smckusick (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 170151898Smckusick if (*cp == '\\') 170251898Smckusick cont_line = 1; 170351898Smckusick cp--; 170451898Smckusick len--; 170551898Smckusick } 170651898Smckusick *++cp = '\0'; 170751898Smckusick if (len > 0) { 170851898Smckusick totlen += len; 170951898Smckusick if (totlen >= LINESIZ) { 171051898Smckusick syslog(LOG_ERR, "Exports line too long"); 171151898Smckusick exit(2); 171251898Smckusick } 171351898Smckusick p = cp; 171451898Smckusick } 171551898Smckusick } while (totlen == 0 || cont_line); 171651898Smckusick return (1); 171744015Smckusick } 171844015Smckusick 171951667Smckusick /* 172051667Smckusick * Parse a description of a credential. 172151667Smckusick */ 172266163Spendry void 172351667Smckusick parsecred(namelist, cr) 172451667Smckusick char *namelist; 172566163Spendry struct ucred *cr; 172651667Smckusick { 172766163Spendry char *name; 172866163Spendry int cnt; 172951667Smckusick char *names; 173051667Smckusick struct passwd *pw; 173151667Smckusick struct group *gr; 173251667Smckusick int ngroups, groups[NGROUPS + 1]; 173351667Smckusick 173451667Smckusick /* 173551667Smckusick * Set up the unpriviledged user. 173651667Smckusick */ 173751667Smckusick cr->cr_ref = 1; 173851667Smckusick cr->cr_uid = -2; 173951667Smckusick cr->cr_groups[0] = -2; 174051667Smckusick cr->cr_ngroups = 1; 174151667Smckusick /* 174251667Smckusick * Get the user's password table entry. 174351667Smckusick */ 174451667Smckusick names = strsep(&namelist, " \t\n"); 174551667Smckusick name = strsep(&names, ":"); 174651667Smckusick if (isdigit(*name) || *name == '-') 174751667Smckusick pw = getpwuid(atoi(name)); 174851667Smckusick else 174951667Smckusick pw = getpwnam(name); 175051667Smckusick /* 175151667Smckusick * Credentials specified as those of a user. 175251667Smckusick */ 175351667Smckusick if (names == NULL) { 175451667Smckusick if (pw == NULL) { 175566163Spendry syslog(LOG_ERR, "Unknown user: %s", name); 175651667Smckusick return; 175751667Smckusick } 175851667Smckusick cr->cr_uid = pw->pw_uid; 175951667Smckusick ngroups = NGROUPS + 1; 176051667Smckusick if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 176166163Spendry syslog(LOG_ERR, "Too many groups"); 176251667Smckusick /* 176351667Smckusick * Convert from int's to gid_t's and compress out duplicate 176451667Smckusick */ 176551667Smckusick cr->cr_ngroups = ngroups - 1; 176651667Smckusick cr->cr_groups[0] = groups[0]; 176751667Smckusick for (cnt = 2; cnt < ngroups; cnt++) 176851667Smckusick cr->cr_groups[cnt - 1] = groups[cnt]; 176951667Smckusick return; 177051667Smckusick } 177151667Smckusick /* 177251667Smckusick * Explicit credential specified as a colon separated list: 177351667Smckusick * uid:gid:gid:... 177451667Smckusick */ 177551667Smckusick if (pw != NULL) 177651667Smckusick cr->cr_uid = pw->pw_uid; 177751667Smckusick else if (isdigit(*name) || *name == '-') 177851667Smckusick cr->cr_uid = atoi(name); 177951667Smckusick else { 178066163Spendry syslog(LOG_ERR, "Unknown user: %s", name); 178151667Smckusick return; 178251667Smckusick } 178351667Smckusick cr->cr_ngroups = 0; 178451667Smckusick while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 178551667Smckusick name = strsep(&names, ":"); 178651667Smckusick if (isdigit(*name) || *name == '-') { 178751667Smckusick cr->cr_groups[cr->cr_ngroups++] = atoi(name); 178851667Smckusick } else { 178951667Smckusick if ((gr = getgrnam(name)) == NULL) { 179066163Spendry syslog(LOG_ERR, "Unknown group: %s", name); 179151667Smckusick continue; 179251667Smckusick } 179351667Smckusick cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 179451667Smckusick } 179551667Smckusick } 179651667Smckusick if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 179766163Spendry syslog(LOG_ERR, "Too many groups"); 179851667Smckusick } 179951667Smckusick 180044015Smckusick #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 180144015Smckusick /* 180244015Smckusick * Routines that maintain the remote mounttab 180344015Smckusick */ 180451667Smckusick void 180551667Smckusick get_mountlist() 180644015Smckusick { 180766163Spendry struct mountlist *mlp, **mlpp; 1808*68996Sbostic char *host, *dirp, *cp; 180944015Smckusick int len; 181044015Smckusick char str[STRSIZ]; 181144015Smckusick FILE *mlfile; 181244015Smckusick 181351712Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 181451667Smckusick syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 181544015Smckusick return; 181644015Smckusick } 181744015Smckusick mlpp = &mlhead; 181844015Smckusick while (fgets(str, STRSIZ, mlfile) != NULL) { 1819*68996Sbostic cp = str; 1820*68996Sbostic host = strsep(&cp, " \t\n"); 1821*68996Sbostic dirp = strsep(&cp, " \t\n"); 1822*68996Sbostic if (host == NULL || dirp == NULL) 182344015Smckusick continue; 182444015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1825*68996Sbostic strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 1826*68996Sbostic mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 1827*68996Sbostic strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 1828*68996Sbostic mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 182966163Spendry mlp->ml_next = (struct mountlist *)NULL; 183044015Smckusick *mlpp = mlp; 183144015Smckusick mlpp = &mlp->ml_next; 183244015Smckusick } 183344015Smckusick fclose(mlfile); 183444015Smckusick } 183544015Smckusick 183651667Smckusick void 183751667Smckusick del_mlist(hostp, dirp) 183866163Spendry char *hostp, *dirp; 183944015Smckusick { 184066163Spendry struct mountlist *mlp, **mlpp; 184151712Smckusick struct mountlist *mlp2; 184244015Smckusick FILE *mlfile; 184344015Smckusick int fnd = 0; 184444015Smckusick 184544015Smckusick mlpp = &mlhead; 184644015Smckusick mlp = mlhead; 184744015Smckusick while (mlp) { 184844015Smckusick if (!strcmp(mlp->ml_host, hostp) && 184944015Smckusick (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 185044015Smckusick fnd = 1; 185151712Smckusick mlp2 = mlp; 185251712Smckusick *mlpp = mlp = mlp->ml_next; 185351712Smckusick free((caddr_t)mlp2); 185451712Smckusick } else { 185551712Smckusick mlpp = &mlp->ml_next; 185651712Smckusick mlp = mlp->ml_next; 185739681Smckusick } 185839681Smckusick } 185944015Smckusick if (fnd) { 186044015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 186151898Smckusick syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 186244015Smckusick return; 186344015Smckusick } 186444015Smckusick mlp = mlhead; 186544015Smckusick while (mlp) { 186644015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 186744015Smckusick mlp = mlp->ml_next; 186844015Smckusick } 186944015Smckusick fclose(mlfile); 187044015Smckusick } 187139681Smckusick } 187244015Smckusick 187351667Smckusick void 187451667Smckusick add_mlist(hostp, dirp) 187566163Spendry char *hostp, *dirp; 187644015Smckusick { 187766163Spendry struct mountlist *mlp, **mlpp; 187844015Smckusick FILE *mlfile; 187944015Smckusick 188044015Smckusick mlpp = &mlhead; 188144015Smckusick mlp = mlhead; 188244015Smckusick while (mlp) { 188344015Smckusick if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 188444015Smckusick return; 188544015Smckusick mlpp = &mlp->ml_next; 188644015Smckusick mlp = mlp->ml_next; 188744015Smckusick } 188844015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 188944015Smckusick strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 189044015Smckusick mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 189144015Smckusick strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 189244015Smckusick mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 189366163Spendry mlp->ml_next = (struct mountlist *)NULL; 189444015Smckusick *mlpp = mlp; 189544015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 189651898Smckusick syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 189744015Smckusick return; 189844015Smckusick } 189944015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 190044015Smckusick fclose(mlfile); 190144015Smckusick } 190244015Smckusick 190344015Smckusick /* 190444015Smckusick * This function is called via. SIGTERM when the system is going down. 190544015Smckusick * It sends a broadcast RPCMNT_UMNTALL. 190644015Smckusick */ 190746709Sbostic void 190844015Smckusick send_umntall() 190944015Smckusick { 191044015Smckusick (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 191144015Smckusick xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 191251667Smckusick exit(0); 191344015Smckusick } 191444015Smckusick 191566163Spendry int 191644015Smckusick umntall_each(resultsp, raddr) 191744015Smckusick caddr_t resultsp; 191844015Smckusick struct sockaddr_in *raddr; 191944015Smckusick { 192044015Smckusick return (1); 192144015Smckusick } 192244015Smckusick 192344015Smckusick /* 192451667Smckusick * Free up a group list. 192551667Smckusick */ 192651667Smckusick void 192751667Smckusick free_grp(grp) 192866163Spendry struct grouplist *grp; 192951667Smckusick { 193066163Spendry char **addrp; 193151667Smckusick 193251898Smckusick if (grp->gr_type == GT_HOST) { 193351712Smckusick if (grp->gr_ptr.gt_hostent->h_name) { 193451712Smckusick addrp = grp->gr_ptr.gt_hostent->h_addr_list; 193551712Smckusick while (addrp && *addrp) 193651712Smckusick free(*addrp++); 193751712Smckusick free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 193851712Smckusick free(grp->gr_ptr.gt_hostent->h_name); 193951712Smckusick } 194051667Smckusick free((caddr_t)grp->gr_ptr.gt_hostent); 194151898Smckusick } else if (grp->gr_type == GT_NET) { 194251898Smckusick if (grp->gr_ptr.gt_net.nt_name) 194351898Smckusick free(grp->gr_ptr.gt_net.nt_name); 194451667Smckusick } 194551667Smckusick #ifdef ISO 194651898Smckusick else if (grp->gr_type == GT_ISO) 194751667Smckusick free((caddr_t)grp->gr_ptr.gt_isoaddr); 194851667Smckusick #endif 194951667Smckusick free((caddr_t)grp); 195051667Smckusick } 195151667Smckusick 195251711Smckusick #ifdef DEBUG 195351711Smckusick void 195451711Smckusick SYSLOG(int pri, const char *fmt, ...) 195551711Smckusick { 195651711Smckusick va_list ap; 195751711Smckusick 195851711Smckusick va_start(ap, fmt); 195951711Smckusick vfprintf(stderr, fmt, ap); 196051711Smckusick va_end(ap); 196151711Smckusick } 196251711Smckusick #endif /* DEBUG */ 196351898Smckusick 196451898Smckusick /* 196551898Smckusick * Check options for consistency. 196651898Smckusick */ 196766163Spendry int 196851898Smckusick check_options(dp) 196951898Smckusick struct dirlist *dp; 197051898Smckusick { 197151898Smckusick 197266163Spendry if (dp == (struct dirlist *)NULL) 197351898Smckusick return (1); 197451898Smckusick if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 197551898Smckusick (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 197651898Smckusick (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 197751898Smckusick syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 197851898Smckusick return (1); 197951898Smckusick } 198051898Smckusick if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 198151898Smckusick syslog(LOG_ERR, "-mask requires -net"); 198251898Smckusick return (1); 198351898Smckusick } 198451898Smckusick if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 198551898Smckusick syslog(LOG_ERR, "-net and -iso mutually exclusive"); 198651898Smckusick return (1); 198751898Smckusick } 198851898Smckusick if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 198951898Smckusick syslog(LOG_ERR, "-alldir has multiple directories"); 199051898Smckusick return (1); 199151898Smckusick } 199251898Smckusick return (0); 199351898Smckusick } 199465940Sbostic 199565940Sbostic /* 199665940Sbostic * Check an absolute directory path for any symbolic links. Return true 199765940Sbostic * if no symbolic links are found. 199865940Sbostic */ 199965940Sbostic int 200065940Sbostic check_dirpath(dirp) 200166163Spendry char *dirp; 200265940Sbostic { 200366163Spendry char *cp; 200465940Sbostic int ret = 1; 200565940Sbostic struct stat sb; 200665940Sbostic 200765940Sbostic cp = dirp + 1; 200865940Sbostic while (*cp && ret) { 200965940Sbostic if (*cp == '/') { 201065940Sbostic *cp = '\0'; 201167383Smkm if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 201265940Sbostic ret = 0; 201365940Sbostic *cp = '/'; 201465940Sbostic } 201565940Sbostic cp++; 201665940Sbostic } 201767383Smkm if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 201865940Sbostic ret = 0; 201965940Sbostic return (ret); 202065940Sbostic } 202168645Smckusick 202268645Smckusick /* 202368645Smckusick * Just translate an ascii string to an integer. 202468645Smckusick */ 202568645Smckusick int 202668645Smckusick get_num(cp) 202768645Smckusick register char *cp; 202868645Smckusick { 202968645Smckusick register int res = 0; 203068645Smckusick 203168645Smckusick while (*cp) { 203268645Smckusick if (*cp < '0' || *cp > '9') 203368645Smckusick return (-1); 203468645Smckusick res = res * 10 + (*cp++ - '0'); 203568645Smckusick } 203668645Smckusick return (res); 203768645Smckusick } 2038