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*68685Smckusick static char sccsid[] = "@(#)mountd.c 8.13 (Berkeley) 03/30/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 226*68685Smckusick 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]; 306*68685Smckusick int bad = ENOENT, defset, hostset; 307*68685Smckusick sigset_t sighup_mask; 30838460Smckusick 309*68685Smckusick sigemptyset(&sighup_mask); 310*68685Smckusick 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 */ 348*68685Smckusick 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 */ 36268645Smckusick bzero((caddr_t)&fhr.fhr_fh, 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"); 369*68685Smckusick 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 } 389*68685Smckusick 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; 515*68685Smckusick int putdef; 516*68685Smckusick sigset_t sighup_mask; 51738460Smckusick 518*68685Smckusick sigemptyset(&sighup_mask); 519*68685Smckusick sigaddset(&sighup_mask, SIGHUP); 520*68685Smckusick 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 } 532*68685Smckusick sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 53338460Smckusick if (!xdr_bool(xdrsp, &false)) 53438460Smckusick return (0); 53538460Smckusick return (1); 53638460Smckusick errout: 537*68685Smckusick 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(); 90651898Smckusick bzero((caddr_t)ep, 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(); 92151898Smckusick bzero((caddr_t)gp, 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; 121351898Smckusick if (cpoptend = index(cpopt, ',')) { 121451898Smckusick *cpoptend++ = '\0'; 121551898Smckusick if (cpoptarg = index(cpopt, '=')) 121651898Smckusick *cpoptarg++ = '\0'; 121751898Smckusick } else { 121851898Smckusick if (cpoptarg = index(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(); 134451898Smckusick bcopy((caddr_t)hp, (caddr_t)nhp, 134551898Smckusick sizeof(struct hostent)); 134651898Smckusick i = strlen(hp->h_name)+1; 134751898Smckusick nhp->h_name = (char *)malloc(i); 134866163Spendry if (nhp->h_name == (char *)NULL) 134951898Smckusick out_of_mem(); 135051898Smckusick bcopy(hp->h_name, nhp->h_name, i); 135151898Smckusick addrp = hp->h_addr_list; 135251898Smckusick i = 1; 135351898Smckusick while (*addrp++) 135451898Smckusick i++; 135551898Smckusick naddrp = nhp->h_addr_list = (char **) 135651898Smckusick malloc(i*sizeof(char *)); 135766163Spendry if (naddrp == (char **)NULL) 135851898Smckusick out_of_mem(); 135951898Smckusick addrp = hp->h_addr_list; 136051898Smckusick while (*addrp) { 136151898Smckusick *naddrp = (char *) 136251898Smckusick malloc(hp->h_length); 136366163Spendry if (*naddrp == (char *)NULL) 136451898Smckusick out_of_mem(); 136551898Smckusick bcopy(*addrp, *naddrp, 136651898Smckusick hp->h_length); 136751898Smckusick addrp++; 136851898Smckusick naddrp++; 136951898Smckusick } 137066163Spendry *naddrp = (char *)NULL; 137153150Smckusick if (debug) 137253150Smckusick fprintf(stderr, "got host %s\n", hp->h_name); 137351898Smckusick return (0); 137451898Smckusick } 137551898Smckusick 137651898Smckusick /* 137751898Smckusick * Free up an exports list component 137851898Smckusick */ 137951898Smckusick void 138051898Smckusick free_exp(ep) 138166163Spendry struct exportlist *ep; 138251898Smckusick { 138351898Smckusick 138451898Smckusick if (ep->ex_defdir) { 138551898Smckusick free_host(ep->ex_defdir->dp_hosts); 138651898Smckusick free((caddr_t)ep->ex_defdir); 138751898Smckusick } 138851898Smckusick if (ep->ex_fsdir) 138951898Smckusick free(ep->ex_fsdir); 139051898Smckusick free_dir(ep->ex_dirl); 139151898Smckusick free((caddr_t)ep); 139251898Smckusick } 139351898Smckusick 139451898Smckusick /* 139551898Smckusick * Free hosts. 139651898Smckusick */ 139751898Smckusick void 139851898Smckusick free_host(hp) 139966163Spendry struct hostlist *hp; 140051898Smckusick { 140166163Spendry struct hostlist *hp2; 140251898Smckusick 140351898Smckusick while (hp) { 140451898Smckusick hp2 = hp; 140551898Smckusick hp = hp->ht_next; 140651898Smckusick free((caddr_t)hp2); 140751898Smckusick } 140851898Smckusick } 140951898Smckusick 141051898Smckusick struct hostlist * 141151898Smckusick get_ht() 141251898Smckusick { 141366163Spendry struct hostlist *hp; 141451898Smckusick 141551898Smckusick hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 141666163Spendry if (hp == (struct hostlist *)NULL) 141751898Smckusick out_of_mem(); 141866163Spendry hp->ht_next = (struct hostlist *)NULL; 141968645Smckusick hp->ht_flag = 0; 142051898Smckusick return (hp); 142151898Smckusick } 142251898Smckusick 142351898Smckusick #ifdef ISO 142451898Smckusick /* 142551898Smckusick * Translate an iso address. 142651898Smckusick */ 142751898Smckusick get_isoaddr(cp, grp) 142851898Smckusick char *cp; 142951898Smckusick struct grouplist *grp; 143051898Smckusick { 143151898Smckusick struct iso_addr *isop; 143251898Smckusick struct sockaddr_iso *isoaddr; 143351898Smckusick 143451898Smckusick if (grp->gr_type != GT_NULL) 143551898Smckusick return (1); 143651898Smckusick if ((isop = iso_addr(cp)) == NULL) { 143751898Smckusick syslog(LOG_ERR, 143851898Smckusick "iso_addr failed, ignored"); 143951898Smckusick return (1); 144051898Smckusick } 144151898Smckusick isoaddr = (struct sockaddr_iso *) 144251898Smckusick malloc(sizeof (struct sockaddr_iso)); 144366163Spendry if (isoaddr == (struct sockaddr_iso *)NULL) 144451898Smckusick out_of_mem(); 144551898Smckusick bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 144651898Smckusick bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 144751898Smckusick sizeof (struct iso_addr)); 144851898Smckusick isoaddr->siso_len = sizeof (struct sockaddr_iso); 144951898Smckusick isoaddr->siso_family = AF_ISO; 145051898Smckusick grp->gr_type = GT_ISO; 145151898Smckusick grp->gr_ptr.gt_isoaddr = isoaddr; 145251898Smckusick return (0); 145351898Smckusick } 145451898Smckusick #endif /* ISO */ 145551898Smckusick 145651898Smckusick /* 145751898Smckusick * Out of memory, fatal 145851898Smckusick */ 145951898Smckusick void 146051898Smckusick out_of_mem() 146151898Smckusick { 146251898Smckusick 146351898Smckusick syslog(LOG_ERR, "Out of memory"); 146451667Smckusick exit(2); 146551667Smckusick } 146651667Smckusick 146751898Smckusick /* 146851898Smckusick * Do the mount syscall with the update flag to push the export info into 146951898Smckusick * the kernel. 147051898Smckusick */ 147166163Spendry int 147251898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 147351667Smckusick struct exportlist *ep; 147451667Smckusick struct grouplist *grp; 147551898Smckusick int exflags; 147651667Smckusick struct ucred *anoncrp; 147751898Smckusick char *dirp; 147851898Smckusick int dirplen; 147951898Smckusick struct statfs *fsb; 148051667Smckusick { 148166163Spendry char *cp = (char *)NULL; 148266163Spendry u_long **addrp; 148351898Smckusick int done; 148466163Spendry char savedc = '\0'; 148551898Smckusick struct sockaddr_in sin, imask; 148665713Shibler union { 148765713Shibler struct ufs_args ua; 148865713Shibler struct iso_args ia; 148965713Shibler struct mfs_args ma; 149065713Shibler } args; 149151898Smckusick u_long net; 149251667Smckusick 149365713Shibler args.ua.fspec = 0; 149465713Shibler args.ua.export.ex_flags = exflags; 149565713Shibler args.ua.export.ex_anon = *anoncrp; 149655878Smckusick bzero((char *)&sin, sizeof(sin)); 149755878Smckusick bzero((char *)&imask, sizeof(imask)); 149851667Smckusick sin.sin_family = AF_INET; 149951667Smckusick sin.sin_len = sizeof(sin); 150051898Smckusick imask.sin_family = AF_INET; 150151898Smckusick imask.sin_len = sizeof(sin); 150251898Smckusick if (grp->gr_type == GT_HOST) 150351667Smckusick addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 150451898Smckusick else 150566163Spendry addrp = (u_long **)NULL; 150651667Smckusick done = FALSE; 150751898Smckusick while (!done) { 150851898Smckusick switch (grp->gr_type) { 150951898Smckusick case GT_HOST: 151064903Smckusick if (addrp) { 151151712Smckusick sin.sin_addr.s_addr = **addrp; 151265713Shibler args.ua.export.ex_addrlen = sizeof(sin); 151364903Smckusick } else 151465713Shibler args.ua.export.ex_addrlen = 0; 151565713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 151665713Shibler args.ua.export.ex_masklen = 0; 151751898Smckusick break; 151851898Smckusick case GT_NET: 151951898Smckusick if (grp->gr_ptr.gt_net.nt_mask) 152051898Smckusick imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 152151898Smckusick else { 152251898Smckusick net = ntohl(grp->gr_ptr.gt_net.nt_net); 152351898Smckusick if (IN_CLASSA(net)) 152451898Smckusick imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 152551898Smckusick else if (IN_CLASSB(net)) 152651898Smckusick imask.sin_addr.s_addr = 152751898Smckusick inet_addr("255.255.0.0"); 152851898Smckusick else 152951898Smckusick imask.sin_addr.s_addr = 153051898Smckusick inet_addr("255.255.255.0"); 153151898Smckusick grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 153251898Smckusick } 153351898Smckusick sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 153465713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 153565713Shibler args.ua.export.ex_addrlen = sizeof (sin); 153665713Shibler args.ua.export.ex_mask = (struct sockaddr *)&imask; 153765713Shibler args.ua.export.ex_masklen = sizeof (imask); 153851898Smckusick break; 153951667Smckusick #ifdef ISO 154051898Smckusick case GT_ISO: 154165713Shibler args.ua.export.ex_addr = 154265713Shibler (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 154365713Shibler args.ua.export.ex_addrlen = 154465713Shibler sizeof(struct sockaddr_iso); 154565713Shibler args.ua.export.ex_masklen = 0; 154651898Smckusick break; 154751667Smckusick #endif /* ISO */ 154851898Smckusick default: 154951667Smckusick syslog(LOG_ERR, "Bad grouptype"); 155051898Smckusick if (cp) 155151898Smckusick *cp = savedc; 155251898Smckusick return (1); 155351898Smckusick }; 155452109Smckusick 155552109Smckusick /* 155652109Smckusick * XXX: 155752109Smckusick * Maybe I should just use the fsb->f_mntonname path instead 155852109Smckusick * of looping back up the dirp to the mount point?? 155952109Smckusick * Also, needs to know how to export all types of local 156068645Smckusick * exportable file systems and not just "ufs". 156152109Smckusick */ 156268645Smckusick while (mount(fsb->f_fstypename, dirp, 156352109Smckusick fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 156451898Smckusick if (cp) 156551898Smckusick *cp-- = savedc; 156651898Smckusick else 156751898Smckusick cp = dirp + dirplen - 1; 156851667Smckusick if (errno == EPERM) { 156951667Smckusick syslog(LOG_ERR, 157051898Smckusick "Can't change attributes for %s.\n", dirp); 157151898Smckusick return (1); 157251667Smckusick } 157351898Smckusick if (opt_flags & OP_ALLDIRS) { 157451898Smckusick syslog(LOG_ERR, "Not root dir"); 157551898Smckusick return (1); 157651898Smckusick } 157751667Smckusick /* back up over the last component */ 157851898Smckusick while (*cp == '/' && cp > dirp) 157951667Smckusick cp--; 158051898Smckusick while (*(cp - 1) != '/' && cp > dirp) 158151667Smckusick cp--; 158251898Smckusick if (cp == dirp) { 158351898Smckusick if (debug) 158451667Smckusick fprintf(stderr,"mnt unsucc\n"); 158551898Smckusick syslog(LOG_ERR, "Can't export %s", dirp); 158651898Smckusick return (1); 158751667Smckusick } 158851667Smckusick savedc = *cp; 158951667Smckusick *cp = '\0'; 159051667Smckusick } 159151898Smckusick if (addrp) { 159251667Smckusick ++addrp; 159366163Spendry if (*addrp == (u_long *)NULL) 159451667Smckusick done = TRUE; 159551898Smckusick } else 159651898Smckusick done = TRUE; 159751898Smckusick } 159851898Smckusick if (cp) 159951898Smckusick *cp = savedc; 160051898Smckusick return (0); 160151898Smckusick } 160251898Smckusick 160351898Smckusick /* 160451898Smckusick * Translate a net address. 160551898Smckusick */ 160666163Spendry int 160751898Smckusick get_net(cp, net, maskflg) 160851898Smckusick char *cp; 160951898Smckusick struct netmsk *net; 161051898Smckusick int maskflg; 161151898Smckusick { 161266163Spendry struct netent *np; 161366163Spendry long netaddr; 161451898Smckusick struct in_addr inetaddr, inetaddr2; 161551898Smckusick char *name; 161651898Smckusick 161751898Smckusick if (np = getnetbyname(cp)) 161851898Smckusick inetaddr = inet_makeaddr(np->n_net, 0); 161951898Smckusick else if (isdigit(*cp)) { 162051898Smckusick if ((netaddr = inet_network(cp)) == -1) 162151898Smckusick return (1); 162251898Smckusick inetaddr = inet_makeaddr(netaddr, 0); 162351898Smckusick /* 162451898Smckusick * Due to arbritrary subnet masks, you don't know how many 162551898Smckusick * bits to shift the address to make it into a network, 162651898Smckusick * however you do know how to make a network address into 162751898Smckusick * a host with host == 0 and then compare them. 162851898Smckusick * (What a pest) 162951898Smckusick */ 163051898Smckusick if (!maskflg) { 163151898Smckusick setnetent(0); 163251898Smckusick while (np = getnetent()) { 163351898Smckusick inetaddr2 = inet_makeaddr(np->n_net, 0); 163451898Smckusick if (inetaddr2.s_addr == inetaddr.s_addr) 163551898Smckusick break; 163651898Smckusick } 163751898Smckusick endnetent(); 163851667Smckusick } 163951898Smckusick } else 164051898Smckusick return (1); 164151898Smckusick if (maskflg) 164251898Smckusick net->nt_mask = inetaddr.s_addr; 164351898Smckusick else { 164451898Smckusick if (np) 164551898Smckusick name = np->n_name; 164651898Smckusick else 164751898Smckusick name = inet_ntoa(inetaddr); 164851898Smckusick net->nt_name = (char *)malloc(strlen(name) + 1); 164966163Spendry if (net->nt_name == (char *)NULL) 165051898Smckusick out_of_mem(); 165151898Smckusick strcpy(net->nt_name, name); 165251898Smckusick net->nt_net = inetaddr.s_addr; 165338460Smckusick } 165451898Smckusick return (0); 165538460Smckusick } 165638460Smckusick 165738460Smckusick /* 165838460Smckusick * Parse out the next white space separated field 165938460Smckusick */ 166051667Smckusick void 166138460Smckusick nextfield(cp, endcp) 166238460Smckusick char **cp; 166338460Smckusick char **endcp; 166438460Smckusick { 166566163Spendry char *p; 166638460Smckusick 166738460Smckusick p = *cp; 166838460Smckusick while (*p == ' ' || *p == '\t') 166938460Smckusick p++; 167051898Smckusick if (*p == '\n' || *p == '\0') 167138460Smckusick *cp = *endcp = p; 167251898Smckusick else { 167351898Smckusick *cp = p++; 167451898Smckusick while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 167551898Smckusick p++; 167651898Smckusick *endcp = p; 167738460Smckusick } 167838460Smckusick } 167939681Smckusick 168039681Smckusick /* 168151898Smckusick * Get an exports file line. Skip over blank lines and handle line 168251898Smckusick * continuations. 168339681Smckusick */ 168466163Spendry int 168551898Smckusick get_line() 168639681Smckusick { 168766163Spendry char *p, *cp; 168866163Spendry int len; 168951898Smckusick int totlen, cont_line; 169039681Smckusick 169151898Smckusick /* 169251898Smckusick * Loop around ignoring blank lines and getting all continuation lines. 169351898Smckusick */ 169451898Smckusick p = line; 169551898Smckusick totlen = 0; 169651898Smckusick do { 169751898Smckusick if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 169851898Smckusick return (0); 169951898Smckusick len = strlen(p); 170051898Smckusick cp = p + len - 1; 170151898Smckusick cont_line = 0; 170251898Smckusick while (cp >= p && 170351898Smckusick (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 170451898Smckusick if (*cp == '\\') 170551898Smckusick cont_line = 1; 170651898Smckusick cp--; 170751898Smckusick len--; 170851898Smckusick } 170951898Smckusick *++cp = '\0'; 171051898Smckusick if (len > 0) { 171151898Smckusick totlen += len; 171251898Smckusick if (totlen >= LINESIZ) { 171351898Smckusick syslog(LOG_ERR, "Exports line too long"); 171451898Smckusick exit(2); 171551898Smckusick } 171651898Smckusick p = cp; 171751898Smckusick } 171851898Smckusick } while (totlen == 0 || cont_line); 171951898Smckusick return (1); 172044015Smckusick } 172144015Smckusick 172251667Smckusick /* 172351667Smckusick * Parse a description of a credential. 172451667Smckusick */ 172566163Spendry void 172651667Smckusick parsecred(namelist, cr) 172751667Smckusick char *namelist; 172866163Spendry struct ucred *cr; 172951667Smckusick { 173066163Spendry char *name; 173166163Spendry int cnt; 173251667Smckusick char *names; 173351667Smckusick struct passwd *pw; 173451667Smckusick struct group *gr; 173551667Smckusick int ngroups, groups[NGROUPS + 1]; 173651667Smckusick 173751667Smckusick /* 173851667Smckusick * Set up the unpriviledged user. 173951667Smckusick */ 174051667Smckusick cr->cr_ref = 1; 174151667Smckusick cr->cr_uid = -2; 174251667Smckusick cr->cr_groups[0] = -2; 174351667Smckusick cr->cr_ngroups = 1; 174451667Smckusick /* 174551667Smckusick * Get the user's password table entry. 174651667Smckusick */ 174751667Smckusick names = strsep(&namelist, " \t\n"); 174851667Smckusick name = strsep(&names, ":"); 174951667Smckusick if (isdigit(*name) || *name == '-') 175051667Smckusick pw = getpwuid(atoi(name)); 175151667Smckusick else 175251667Smckusick pw = getpwnam(name); 175351667Smckusick /* 175451667Smckusick * Credentials specified as those of a user. 175551667Smckusick */ 175651667Smckusick if (names == NULL) { 175751667Smckusick if (pw == NULL) { 175866163Spendry syslog(LOG_ERR, "Unknown user: %s", name); 175951667Smckusick return; 176051667Smckusick } 176151667Smckusick cr->cr_uid = pw->pw_uid; 176251667Smckusick ngroups = NGROUPS + 1; 176351667Smckusick if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 176466163Spendry syslog(LOG_ERR, "Too many groups"); 176551667Smckusick /* 176651667Smckusick * Convert from int's to gid_t's and compress out duplicate 176751667Smckusick */ 176851667Smckusick cr->cr_ngroups = ngroups - 1; 176951667Smckusick cr->cr_groups[0] = groups[0]; 177051667Smckusick for (cnt = 2; cnt < ngroups; cnt++) 177151667Smckusick cr->cr_groups[cnt - 1] = groups[cnt]; 177251667Smckusick return; 177351667Smckusick } 177451667Smckusick /* 177551667Smckusick * Explicit credential specified as a colon separated list: 177651667Smckusick * uid:gid:gid:... 177751667Smckusick */ 177851667Smckusick if (pw != NULL) 177951667Smckusick cr->cr_uid = pw->pw_uid; 178051667Smckusick else if (isdigit(*name) || *name == '-') 178151667Smckusick cr->cr_uid = atoi(name); 178251667Smckusick else { 178366163Spendry syslog(LOG_ERR, "Unknown user: %s", name); 178451667Smckusick return; 178551667Smckusick } 178651667Smckusick cr->cr_ngroups = 0; 178751667Smckusick while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 178851667Smckusick name = strsep(&names, ":"); 178951667Smckusick if (isdigit(*name) || *name == '-') { 179051667Smckusick cr->cr_groups[cr->cr_ngroups++] = atoi(name); 179151667Smckusick } else { 179251667Smckusick if ((gr = getgrnam(name)) == NULL) { 179366163Spendry syslog(LOG_ERR, "Unknown group: %s", name); 179451667Smckusick continue; 179551667Smckusick } 179651667Smckusick cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 179751667Smckusick } 179851667Smckusick } 179951667Smckusick if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 180066163Spendry syslog(LOG_ERR, "Too many groups"); 180151667Smckusick } 180251667Smckusick 180344015Smckusick #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 180444015Smckusick /* 180544015Smckusick * Routines that maintain the remote mounttab 180644015Smckusick */ 180751667Smckusick void 180851667Smckusick get_mountlist() 180944015Smckusick { 181066163Spendry struct mountlist *mlp, **mlpp; 181166163Spendry char *eos, *dirp; 181244015Smckusick int len; 181344015Smckusick char str[STRSIZ]; 181444015Smckusick FILE *mlfile; 181544015Smckusick 181651712Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 181751667Smckusick syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 181844015Smckusick return; 181944015Smckusick } 182044015Smckusick mlpp = &mlhead; 182144015Smckusick while (fgets(str, STRSIZ, mlfile) != NULL) { 182244015Smckusick if ((dirp = index(str, '\t')) == NULL && 182344015Smckusick (dirp = index(str, ' ')) == NULL) 182444015Smckusick continue; 182544015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 182644015Smckusick len = dirp-str; 182744015Smckusick if (len > RPCMNT_NAMELEN) 182844015Smckusick len = RPCMNT_NAMELEN; 182944015Smckusick bcopy(str, mlp->ml_host, len); 183044015Smckusick mlp->ml_host[len] = '\0'; 183144015Smckusick while (*dirp == '\t' || *dirp == ' ') 183244015Smckusick dirp++; 183344015Smckusick if ((eos = index(dirp, '\t')) == NULL && 183444015Smckusick (eos = index(dirp, ' ')) == NULL && 183544015Smckusick (eos = index(dirp, '\n')) == NULL) 183644015Smckusick len = strlen(dirp); 183744015Smckusick else 183844015Smckusick len = eos-dirp; 183944015Smckusick if (len > RPCMNT_PATHLEN) 184044015Smckusick len = RPCMNT_PATHLEN; 184144015Smckusick bcopy(dirp, mlp->ml_dirp, len); 184244015Smckusick mlp->ml_dirp[len] = '\0'; 184366163Spendry mlp->ml_next = (struct mountlist *)NULL; 184444015Smckusick *mlpp = mlp; 184544015Smckusick mlpp = &mlp->ml_next; 184644015Smckusick } 184744015Smckusick fclose(mlfile); 184844015Smckusick } 184944015Smckusick 185051667Smckusick void 185151667Smckusick del_mlist(hostp, dirp) 185266163Spendry char *hostp, *dirp; 185344015Smckusick { 185466163Spendry struct mountlist *mlp, **mlpp; 185551712Smckusick struct mountlist *mlp2; 185644015Smckusick FILE *mlfile; 185744015Smckusick int fnd = 0; 185844015Smckusick 185944015Smckusick mlpp = &mlhead; 186044015Smckusick mlp = mlhead; 186144015Smckusick while (mlp) { 186244015Smckusick if (!strcmp(mlp->ml_host, hostp) && 186344015Smckusick (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 186444015Smckusick fnd = 1; 186551712Smckusick mlp2 = mlp; 186651712Smckusick *mlpp = mlp = mlp->ml_next; 186751712Smckusick free((caddr_t)mlp2); 186851712Smckusick } else { 186951712Smckusick mlpp = &mlp->ml_next; 187051712Smckusick mlp = mlp->ml_next; 187139681Smckusick } 187239681Smckusick } 187344015Smckusick if (fnd) { 187444015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 187551898Smckusick syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 187644015Smckusick return; 187744015Smckusick } 187844015Smckusick mlp = mlhead; 187944015Smckusick while (mlp) { 188044015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 188144015Smckusick mlp = mlp->ml_next; 188244015Smckusick } 188344015Smckusick fclose(mlfile); 188444015Smckusick } 188539681Smckusick } 188644015Smckusick 188751667Smckusick void 188851667Smckusick add_mlist(hostp, dirp) 188966163Spendry char *hostp, *dirp; 189044015Smckusick { 189166163Spendry struct mountlist *mlp, **mlpp; 189244015Smckusick FILE *mlfile; 189344015Smckusick 189444015Smckusick mlpp = &mlhead; 189544015Smckusick mlp = mlhead; 189644015Smckusick while (mlp) { 189744015Smckusick if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 189844015Smckusick return; 189944015Smckusick mlpp = &mlp->ml_next; 190044015Smckusick mlp = mlp->ml_next; 190144015Smckusick } 190244015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 190344015Smckusick strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 190444015Smckusick mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 190544015Smckusick strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 190644015Smckusick mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 190766163Spendry mlp->ml_next = (struct mountlist *)NULL; 190844015Smckusick *mlpp = mlp; 190944015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 191051898Smckusick syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 191144015Smckusick return; 191244015Smckusick } 191344015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 191444015Smckusick fclose(mlfile); 191544015Smckusick } 191644015Smckusick 191744015Smckusick /* 191844015Smckusick * This function is called via. SIGTERM when the system is going down. 191944015Smckusick * It sends a broadcast RPCMNT_UMNTALL. 192044015Smckusick */ 192146709Sbostic void 192244015Smckusick send_umntall() 192344015Smckusick { 192444015Smckusick (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 192544015Smckusick xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 192651667Smckusick exit(0); 192744015Smckusick } 192844015Smckusick 192966163Spendry int 193044015Smckusick umntall_each(resultsp, raddr) 193144015Smckusick caddr_t resultsp; 193244015Smckusick struct sockaddr_in *raddr; 193344015Smckusick { 193444015Smckusick return (1); 193544015Smckusick } 193644015Smckusick 193744015Smckusick /* 193851667Smckusick * Free up a group list. 193951667Smckusick */ 194051667Smckusick void 194151667Smckusick free_grp(grp) 194266163Spendry struct grouplist *grp; 194351667Smckusick { 194466163Spendry char **addrp; 194551667Smckusick 194651898Smckusick if (grp->gr_type == GT_HOST) { 194751712Smckusick if (grp->gr_ptr.gt_hostent->h_name) { 194851712Smckusick addrp = grp->gr_ptr.gt_hostent->h_addr_list; 194951712Smckusick while (addrp && *addrp) 195051712Smckusick free(*addrp++); 195151712Smckusick free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 195251712Smckusick free(grp->gr_ptr.gt_hostent->h_name); 195351712Smckusick } 195451667Smckusick free((caddr_t)grp->gr_ptr.gt_hostent); 195551898Smckusick } else if (grp->gr_type == GT_NET) { 195651898Smckusick if (grp->gr_ptr.gt_net.nt_name) 195751898Smckusick free(grp->gr_ptr.gt_net.nt_name); 195851667Smckusick } 195951667Smckusick #ifdef ISO 196051898Smckusick else if (grp->gr_type == GT_ISO) 196151667Smckusick free((caddr_t)grp->gr_ptr.gt_isoaddr); 196251667Smckusick #endif 196351667Smckusick free((caddr_t)grp); 196451667Smckusick } 196551667Smckusick 196651711Smckusick #ifdef DEBUG 196751711Smckusick void 196851711Smckusick SYSLOG(int pri, const char *fmt, ...) 196951711Smckusick { 197051711Smckusick va_list ap; 197151711Smckusick 197251711Smckusick va_start(ap, fmt); 197351711Smckusick vfprintf(stderr, fmt, ap); 197451711Smckusick va_end(ap); 197551711Smckusick } 197651711Smckusick #endif /* DEBUG */ 197751898Smckusick 197851898Smckusick /* 197951898Smckusick * Check options for consistency. 198051898Smckusick */ 198166163Spendry int 198251898Smckusick check_options(dp) 198351898Smckusick struct dirlist *dp; 198451898Smckusick { 198551898Smckusick 198666163Spendry if (dp == (struct dirlist *)NULL) 198751898Smckusick return (1); 198851898Smckusick if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 198951898Smckusick (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 199051898Smckusick (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 199151898Smckusick syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 199251898Smckusick return (1); 199351898Smckusick } 199451898Smckusick if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 199551898Smckusick syslog(LOG_ERR, "-mask requires -net"); 199651898Smckusick return (1); 199751898Smckusick } 199851898Smckusick if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 199951898Smckusick syslog(LOG_ERR, "-net and -iso mutually exclusive"); 200051898Smckusick return (1); 200151898Smckusick } 200251898Smckusick if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 200351898Smckusick syslog(LOG_ERR, "-alldir has multiple directories"); 200451898Smckusick return (1); 200551898Smckusick } 200651898Smckusick return (0); 200751898Smckusick } 200865940Sbostic 200965940Sbostic /* 201065940Sbostic * Check an absolute directory path for any symbolic links. Return true 201165940Sbostic * if no symbolic links are found. 201265940Sbostic */ 201365940Sbostic int 201465940Sbostic check_dirpath(dirp) 201566163Spendry char *dirp; 201665940Sbostic { 201766163Spendry char *cp; 201865940Sbostic int ret = 1; 201965940Sbostic struct stat sb; 202065940Sbostic 202165940Sbostic cp = dirp + 1; 202265940Sbostic while (*cp && ret) { 202365940Sbostic if (*cp == '/') { 202465940Sbostic *cp = '\0'; 202567383Smkm if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 202665940Sbostic ret = 0; 202765940Sbostic *cp = '/'; 202865940Sbostic } 202965940Sbostic cp++; 203065940Sbostic } 203167383Smkm if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 203265940Sbostic ret = 0; 203365940Sbostic return (ret); 203465940Sbostic } 203568645Smckusick 203668645Smckusick /* 203768645Smckusick * Just translate an ascii string to an integer. 203868645Smckusick */ 203968645Smckusick int 204068645Smckusick get_num(cp) 204168645Smckusick register char *cp; 204268645Smckusick { 204368645Smckusick register int res = 0; 204468645Smckusick 204568645Smckusick while (*cp) { 204668645Smckusick if (*cp < '0' || *cp > '9') 204768645Smckusick return (-1); 204868645Smckusick res = res * 10 + (*cp++ - '0'); 204968645Smckusick } 205068645Smckusick return (res); 205168645Smckusick } 2052