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*68645Smckusick static char sccsid[] = "@(#)mountd.c 8.12 (Berkeley) 03/29/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> 37*68645Smckusick #include <nfs/nfsproto.h> 38*68645Smckusick #include <ufs/ufs/ufsmount.h> 39*68645Smckusick #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 77*68645Smckusick #define DP_HOSTSET 0x2 78*68645Smckusick #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 { 117*68645Smckusick int ht_flag; /* Uses DP_xx bits */ 11851898Smckusick struct grouplist *ht_grp; 11951898Smckusick struct hostlist *ht_next; 12051667Smckusick }; 12151667Smckusick 122*68645Smckusick struct fhreturn { 123*68645Smckusick int fhr_flag; 124*68645Smckusick int fhr_vers; 125*68645Smckusick nfsfh_t fhr_fh; 126*68645Smckusick }; 127*68645Smckusick 12838460Smckusick /* Global defs */ 12966163Spendry char *add_expdir __P((struct dirlist **, char *, int)); 13066163Spendry void add_dlist __P((struct dirlist **, struct dirlist *, 131*68645Smckusick struct grouplist *, int)); 13266163Spendry void add_mlist __P((char *, char *)); 13366163Spendry int check_dirpath __P((char *)); 13466163Spendry int check_options __P((struct dirlist *)); 135*68645Smckusick 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, 139*68645Smckusick 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 *)); 150*68645Smckusick 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)); 169*68645Smckusick 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; 192*68645Smckusick 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 { 223*68645Smckusick SVCXPRT *udptransp, *tcptransp; 22444015Smckusick int c; 22538460Smckusick 226*68645Smckusick while ((c = getopt(argc, argv, "ntr")) != EOF) 22744015Smckusick switch (c) { 22844015Smckusick case 'n': 22967701Smckusick resvport_only = 0; 23044015Smckusick break; 231*68645Smckusick case 'r': 232*68645Smckusick dir_only = 0; 233*68645Smckusick break; 23444015Smckusick default: 235*68645Smckusick 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 } 270*68645Smckusick if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL || 271*68645Smckusick (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) { 27238460Smckusick syslog(LOG_ERR, "Can't create socket"); 27338460Smckusick exit(1); 27438460Smckusick } 275*68645Smckusick pmap_unset(RPCPROG_MNT, 1); 276*68645Smckusick pmap_unset(RPCPROG_MNT, 3); 277*68645Smckusick if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) || 278*68645Smckusick !svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) || 279*68645Smckusick !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP) || 280*68645Smckusick !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; 299*68645Smckusick struct fhreturn fhr; 30038460Smckusick struct stat stb; 30151898Smckusick struct statfs fsb; 30238460Smckusick struct hostent *hp; 30339681Smckusick u_long saddr; 30467701Smckusick u_short sport; 305*68645Smckusick char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 306*68645Smckusick int bad = ENOENT, omask, defset, hostset; 30738460Smckusick 30839681Smckusick saddr = transp->xp_raddr.sin_addr.s_addr; 30967701Smckusick sport = ntohs(transp->xp_raddr.sin_port); 31066163Spendry hp = (struct hostent *)NULL; 31138460Smckusick switch (rqstp->rq_proc) { 31239681Smckusick case NULLPROC: 31366163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 31439681Smckusick syslog(LOG_ERR, "Can't send reply"); 31539681Smckusick return; 31638460Smckusick case RPCMNT_MOUNT: 31767701Smckusick if (sport >= IPPORT_RESERVED && resvport_only) { 31839681Smckusick svcerr_weakauth(transp); 31939681Smckusick return; 32039681Smckusick } 32151667Smckusick if (!svc_getargs(transp, xdr_dir, rpcpath)) { 32238460Smckusick svcerr_decode(transp); 32338460Smckusick return; 32438460Smckusick } 32538460Smckusick 32651667Smckusick /* 327*68645Smckusick * Get the real pathname and make sure it is a directory 328*68645Smckusick * or a regular file if the -r option was specified 329*68645Smckusick * and it exists. 33051667Smckusick */ 33151898Smckusick if (realpath(rpcpath, dirpath) == 0 || 33251898Smckusick stat(dirpath, &stb) < 0 || 333*68645Smckusick (!S_ISDIR(stb.st_mode) && 334*68645Smckusick (dir_only || !S_ISREG(stb.st_mode))) || 33551898Smckusick statfs(dirpath, &fsb) < 0) { 33651667Smckusick chdir("/"); /* Just in case realpath doesn't */ 33751667Smckusick if (debug) 33851898Smckusick fprintf(stderr, "stat failed on %s\n", dirpath); 33938460Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 34038460Smckusick syslog(LOG_ERR, "Can't send reply"); 34138460Smckusick return; 34238460Smckusick } 34338460Smckusick 34438460Smckusick /* Check in the exports list */ 34538460Smckusick omask = sigblock(sigmask(SIGHUP)); 34651898Smckusick ep = ex_search(&fsb.f_fsid); 347*68645Smckusick hostset = defset = 0; 348*68645Smckusick if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 34951898Smckusick ((dp = dirp_search(ep->ex_dirl, dirpath)) && 350*68645Smckusick chk_host(dp, saddr, &defset, &hostset)) || 35151898Smckusick (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 35251898Smckusick scan_tree(ep->ex_dirl, saddr) == 0))) { 353*68645Smckusick if (hostset & DP_HOSTSET) 354*68645Smckusick fhr.fhr_flag = hostset; 355*68645Smckusick else 356*68645Smckusick fhr.fhr_flag = defset; 357*68645Smckusick fhr.fhr_vers = rqstp->rq_vers; 35851667Smckusick /* Get the file handle */ 359*68645Smckusick bzero((caddr_t)&fhr.fhr_fh, sizeof(nfsfh_t)); 360*68645Smckusick if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 36151667Smckusick bad = errno; 36251898Smckusick syslog(LOG_ERR, "Can't get fh for %s", dirpath); 36351667Smckusick if (!svc_sendreply(transp, xdr_long, 36451667Smckusick (caddr_t)&bad)) 36551667Smckusick syslog(LOG_ERR, "Can't send reply"); 36651667Smckusick sigsetmask(omask); 36751667Smckusick return; 36851667Smckusick } 369*68645Smckusick if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr)) 37038460Smckusick syslog(LOG_ERR, "Can't send reply"); 37151667Smckusick if (hp == NULL) 37251667Smckusick hp = gethostbyaddr((caddr_t)&saddr, 37351667Smckusick sizeof(saddr), AF_INET); 37451667Smckusick if (hp) 37551667Smckusick add_mlist(hp->h_name, dirpath); 37651667Smckusick else 37751667Smckusick add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 37851667Smckusick dirpath); 37951667Smckusick if (debug) 38051667Smckusick fprintf(stderr,"Mount successfull.\n"); 38151898Smckusick } else { 38251898Smckusick bad = EACCES; 38351898Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 38451898Smckusick syslog(LOG_ERR, "Can't send reply"); 38538460Smckusick } 38651667Smckusick sigsetmask(omask); 38738460Smckusick return; 38838460Smckusick case RPCMNT_DUMP: 38966163Spendry if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) 39038460Smckusick syslog(LOG_ERR, "Can't send reply"); 39138460Smckusick return; 39238460Smckusick case RPCMNT_UMOUNT: 39367701Smckusick if (sport >= IPPORT_RESERVED && resvport_only) { 39439681Smckusick svcerr_weakauth(transp); 39539681Smckusick return; 39639681Smckusick } 39738460Smckusick if (!svc_getargs(transp, xdr_dir, dirpath)) { 39838460Smckusick svcerr_decode(transp); 39938460Smckusick return; 40038460Smckusick } 40166163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 40238460Smckusick syslog(LOG_ERR, "Can't send reply"); 40344015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 40444015Smckusick if (hp) 40544015Smckusick del_mlist(hp->h_name, dirpath); 40651667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 40738460Smckusick return; 40838460Smckusick case RPCMNT_UMNTALL: 40967701Smckusick if (sport >= IPPORT_RESERVED && resvport_only) { 41039681Smckusick svcerr_weakauth(transp); 41139681Smckusick return; 41239681Smckusick } 41366163Spendry if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 41438460Smckusick syslog(LOG_ERR, "Can't send reply"); 41544015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 41644015Smckusick if (hp) 41766163Spendry del_mlist(hp->h_name, (char *)NULL); 41866163Spendry del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL); 41938460Smckusick return; 42038460Smckusick case RPCMNT_EXPORT: 42166163Spendry if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) 42238460Smckusick syslog(LOG_ERR, "Can't send reply"); 42338460Smckusick return; 42438460Smckusick default: 42538460Smckusick svcerr_noproc(transp); 42638460Smckusick return; 42738460Smckusick } 42838460Smckusick } 42938460Smckusick 43038460Smckusick /* 43138460Smckusick * Xdr conversion for a dirpath string 43238460Smckusick */ 43366163Spendry int 43438460Smckusick xdr_dir(xdrsp, dirp) 43538460Smckusick XDR *xdrsp; 43638460Smckusick char *dirp; 43738460Smckusick { 43838460Smckusick return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 43938460Smckusick } 44038460Smckusick 44138460Smckusick /* 442*68645Smckusick * Xdr routine to generate file handle reply 44338460Smckusick */ 44466163Spendry int 445*68645Smckusick xdr_fhs(xdrsp, cp) 44638460Smckusick XDR *xdrsp; 447*68645Smckusick caddr_t cp; 44838460Smckusick { 449*68645Smckusick register struct fhreturn *fhrp = (struct fhreturn *)cp; 450*68645Smckusick long ok = 0, len, auth; 45138460Smckusick 45238460Smckusick if (!xdr_long(xdrsp, &ok)) 45338460Smckusick return (0); 454*68645Smckusick switch (fhrp->fhr_vers) { 455*68645Smckusick case 1: 456*68645Smckusick return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 457*68645Smckusick case 3: 458*68645Smckusick len = NFSX_V3FH; 459*68645Smckusick if (!xdr_long(xdrsp, &len)) 460*68645Smckusick return (0); 461*68645Smckusick if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 462*68645Smckusick return (0); 463*68645Smckusick if (fhrp->fhr_flag & DP_KERB) 464*68645Smckusick auth = RPCAUTH_KERB4; 465*68645Smckusick else 466*68645Smckusick auth = RPCAUTH_UNIX; 467*68645Smckusick len = 1; 468*68645Smckusick if (!xdr_long(xdrsp, &len)) 469*68645Smckusick return (0); 470*68645Smckusick return (xdr_long(xdrsp, &auth)); 471*68645Smckusick }; 472*68645Smckusick return (0); 47338460Smckusick } 47438460Smckusick 47566163Spendry int 47638460Smckusick xdr_mlist(xdrsp, cp) 47738460Smckusick XDR *xdrsp; 47838460Smckusick caddr_t cp; 47938460Smckusick { 48066163Spendry struct mountlist *mlp; 48138460Smckusick int true = 1; 48238460Smckusick int false = 0; 48338460Smckusick char *strp; 48438460Smckusick 48544015Smckusick mlp = mlhead; 48644015Smckusick while (mlp) { 48744015Smckusick if (!xdr_bool(xdrsp, &true)) 48844015Smckusick return (0); 48944015Smckusick strp = &mlp->ml_host[0]; 49044015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 49144015Smckusick return (0); 49244015Smckusick strp = &mlp->ml_dirp[0]; 49344015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 49444015Smckusick return (0); 49544015Smckusick mlp = mlp->ml_next; 49638460Smckusick } 49738460Smckusick if (!xdr_bool(xdrsp, &false)) 49838460Smckusick return (0); 49938460Smckusick return (1); 50038460Smckusick } 50138460Smckusick 50238460Smckusick /* 50338460Smckusick * Xdr conversion for export list 50438460Smckusick */ 50566163Spendry int 50638460Smckusick xdr_explist(xdrsp, cp) 50738460Smckusick XDR *xdrsp; 50838460Smckusick caddr_t cp; 50938460Smckusick { 51066163Spendry struct exportlist *ep; 51138460Smckusick int false = 0; 51264903Smckusick int omask, putdef; 51338460Smckusick 51438460Smckusick omask = sigblock(sigmask(SIGHUP)); 51551898Smckusick ep = exphead; 51651898Smckusick while (ep) { 51764903Smckusick putdef = 0; 51864903Smckusick if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 51938460Smckusick goto errout; 52064903Smckusick if (ep->ex_defdir && putdef == 0 && 52166163Spendry put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 52264903Smckusick &putdef)) 52364903Smckusick goto errout; 52438460Smckusick ep = ep->ex_next; 52538460Smckusick } 52638460Smckusick sigsetmask(omask); 52738460Smckusick if (!xdr_bool(xdrsp, &false)) 52838460Smckusick return (0); 52938460Smckusick return (1); 53038460Smckusick errout: 53138460Smckusick sigsetmask(omask); 53238460Smckusick return (0); 53338460Smckusick } 53438460Smckusick 53551898Smckusick /* 53651898Smckusick * Called from xdr_explist() to traverse the tree and export the 53751898Smckusick * directory paths. 53851898Smckusick */ 53966163Spendry int 54064903Smckusick put_exlist(dp, xdrsp, adp, putdefp) 54166163Spendry struct dirlist *dp; 54251898Smckusick XDR *xdrsp; 54351898Smckusick struct dirlist *adp; 54464903Smckusick int *putdefp; 54551898Smckusick { 54666163Spendry struct grouplist *grp; 54766163Spendry struct hostlist *hp; 54851898Smckusick int true = 1; 54951898Smckusick int false = 0; 55051898Smckusick int gotalldir = 0; 55151898Smckusick char *strp; 55251898Smckusick 55351898Smckusick if (dp) { 55464903Smckusick if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 55551898Smckusick return (1); 55651898Smckusick if (!xdr_bool(xdrsp, &true)) 55751898Smckusick return (1); 55851898Smckusick strp = dp->dp_dirp; 55951898Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 56051898Smckusick return (1); 56164903Smckusick if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 56251898Smckusick gotalldir = 1; 56364903Smckusick *putdefp = 1; 56464903Smckusick } 56551898Smckusick if ((dp->dp_flag & DP_DEFSET) == 0 && 56651898Smckusick (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 56751898Smckusick hp = dp->dp_hosts; 56851898Smckusick while (hp) { 56951898Smckusick grp = hp->ht_grp; 57051898Smckusick if (grp->gr_type == GT_HOST) { 57151898Smckusick if (!xdr_bool(xdrsp, &true)) 57251898Smckusick return (1); 57351898Smckusick strp = grp->gr_ptr.gt_hostent->h_name; 57451898Smckusick if (!xdr_string(xdrsp, &strp, 57551898Smckusick RPCMNT_NAMELEN)) 57651898Smckusick return (1); 57751898Smckusick } else if (grp->gr_type == GT_NET) { 57851898Smckusick if (!xdr_bool(xdrsp, &true)) 57951898Smckusick return (1); 58051898Smckusick strp = grp->gr_ptr.gt_net.nt_name; 58151898Smckusick if (!xdr_string(xdrsp, &strp, 58251898Smckusick RPCMNT_NAMELEN)) 58351898Smckusick return (1); 58451898Smckusick } 58551898Smckusick hp = hp->ht_next; 58666163Spendry if (gotalldir && hp == (struct hostlist *)NULL) { 58751898Smckusick hp = adp->dp_hosts; 58851898Smckusick gotalldir = 0; 58951898Smckusick } 59051898Smckusick } 59151898Smckusick } 59251898Smckusick if (!xdr_bool(xdrsp, &false)) 59351898Smckusick return (1); 59464903Smckusick if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 59551898Smckusick return (1); 59651898Smckusick } 59751898Smckusick return (0); 59851898Smckusick } 59951898Smckusick 60038460Smckusick #define LINESIZ 10240 60138460Smckusick char line[LINESIZ]; 60251898Smckusick FILE *exp_file; 60338460Smckusick 60438460Smckusick /* 60538460Smckusick * Get the export list 60638460Smckusick */ 60746709Sbostic void 60838460Smckusick get_exportlist() 60938460Smckusick { 61066163Spendry struct exportlist *ep, *ep2; 61166163Spendry struct grouplist *grp, *tgrp; 61251898Smckusick struct exportlist **epp; 61351898Smckusick struct dirlist *dirhead; 61452109Smckusick struct statfs fsb, *fsp; 61551898Smckusick struct hostent *hpe; 61651898Smckusick struct ucred anon; 61753150Smckusick char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 61853150Smckusick int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 61938460Smckusick 62038460Smckusick /* 62138460Smckusick * First, get rid of the old list 62238460Smckusick */ 62351898Smckusick ep = exphead; 62451898Smckusick while (ep) { 62538460Smckusick ep2 = ep; 62638460Smckusick ep = ep->ex_next; 62744015Smckusick free_exp(ep2); 62838460Smckusick } 62966163Spendry exphead = (struct exportlist *)NULL; 63038460Smckusick 63151898Smckusick grp = grphead; 63251898Smckusick while (grp) { 63351898Smckusick tgrp = grp; 63451898Smckusick grp = grp->gr_next; 63551898Smckusick free_grp(tgrp); 63651667Smckusick } 63766163Spendry grphead = (struct grouplist *)NULL; 63851667Smckusick 63938460Smckusick /* 64052109Smckusick * And delete exports that are in the kernel for all local 64152109Smckusick * file systems. 64252109Smckusick * XXX: Should know how to handle all local exportable file systems 643*68645Smckusick * instead of just "ufs". 64452109Smckusick */ 64553214Smckusick num = getmntinfo(&fsp, MNT_NOWAIT); 64652109Smckusick for (i = 0; i < num; i++) { 64765713Shibler union { 64865713Shibler struct ufs_args ua; 64965713Shibler struct iso_args ia; 65065713Shibler struct mfs_args ma; 65165713Shibler } targs; 65265713Shibler 653*68645Smckusick if (!strcmp(fsp->f_fstypename, "mfs") || 654*68645Smckusick !strcmp(fsp->f_fstypename, "ufs") || 655*68645Smckusick !strcmp(fsp->f_fstypename, "cd9660")) { 65665863Sbostic targs.ua.fspec = NULL; 65765713Shibler targs.ua.export.ex_flags = MNT_DELEXPORT; 658*68645Smckusick if (mount(fsp->f_fstypename, fsp->f_mntonname, 65965713Shibler fsp->f_flags | MNT_UPDATE, 66065713Shibler (caddr_t)&targs) < 0) 66165713Shibler syslog(LOG_ERR, "Can't delete exports for %s", 66252109Smckusick fsp->f_mntonname); 66352109Smckusick } 66452109Smckusick fsp++; 66552109Smckusick } 66652109Smckusick 66752109Smckusick /* 66838460Smckusick * Read in the exports file and build the list, calling 66951667Smckusick * mount() as we go along to push the export rules into the kernel. 67038460Smckusick */ 67151898Smckusick if ((exp_file = fopen(exname, "r")) == NULL) { 67238460Smckusick syslog(LOG_ERR, "Can't open %s", exname); 67338460Smckusick exit(2); 67438460Smckusick } 67566163Spendry dirhead = (struct dirlist *)NULL; 67651898Smckusick while (get_line()) { 67751667Smckusick if (debug) 67851667Smckusick fprintf(stderr,"Got line %s\n",line); 67938460Smckusick cp = line; 68038460Smckusick nextfield(&cp, &endcp); 68151667Smckusick if (*cp == '#') 68251667Smckusick goto nextline; 68351898Smckusick 68451898Smckusick /* 68551898Smckusick * Set defaults. 68651898Smckusick */ 68751898Smckusick has_host = FALSE; 68851898Smckusick anon = def_anon; 68951667Smckusick exflags = MNT_EXPORTED; 69051898Smckusick got_nondir = 0; 69151898Smckusick opt_flags = 0; 69266163Spendry ep = (struct exportlist *)NULL; 69344015Smckusick 69444015Smckusick /* 69544015Smckusick * Create new exports list entry 69644015Smckusick */ 69738460Smckusick len = endcp-cp; 69853150Smckusick tgrp = grp = get_grp(); 69951898Smckusick while (len > 0) { 70051898Smckusick if (len > RPCMNT_NAMELEN) { 70153150Smckusick getexp_err(ep, tgrp); 70251898Smckusick goto nextline; 70351667Smckusick } 70445271Smckusick if (*cp == '-') { 70566163Spendry if (ep == (struct exportlist *)NULL) { 70653150Smckusick getexp_err(ep, tgrp); 70751898Smckusick goto nextline; 70851898Smckusick } 70951898Smckusick if (debug) 71051898Smckusick fprintf(stderr, "doing opt %s\n", cp); 71151898Smckusick got_nondir = 1; 71251898Smckusick if (do_opt(&cp, &endcp, ep, grp, &has_host, 71351898Smckusick &exflags, &anon)) { 71453150Smckusick getexp_err(ep, tgrp); 71551898Smckusick goto nextline; 71651898Smckusick } 71751898Smckusick } else if (*cp == '/') { 71851898Smckusick savedc = *endcp; 71951898Smckusick *endcp = '\0'; 72065940Sbostic if (check_dirpath(cp) && 72151898Smckusick statfs(cp, &fsb) >= 0) { 72251898Smckusick if (got_nondir) { 72351898Smckusick syslog(LOG_ERR, "Dirs must be first"); 72453150Smckusick getexp_err(ep, tgrp); 72551898Smckusick goto nextline; 72651898Smckusick } 72751898Smckusick if (ep) { 72851898Smckusick if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 72951898Smckusick ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 73053150Smckusick getexp_err(ep, tgrp); 73151898Smckusick goto nextline; 73251898Smckusick } 73351667Smckusick } else { 73451898Smckusick /* 73551898Smckusick * See if this directory is already 73651898Smckusick * in the list. 73751898Smckusick */ 73851898Smckusick ep = ex_search(&fsb.f_fsid); 73966163Spendry if (ep == (struct exportlist *)NULL) { 74051898Smckusick ep = get_exp(); 74151898Smckusick ep->ex_fs = fsb.f_fsid; 74251898Smckusick ep->ex_fsdir = (char *) 74351898Smckusick malloc(strlen(fsb.f_mntonname) + 1); 74451898Smckusick if (ep->ex_fsdir) 74551898Smckusick strcpy(ep->ex_fsdir, 74651898Smckusick fsb.f_mntonname); 74751898Smckusick else 74851898Smckusick out_of_mem(); 74951898Smckusick if (debug) 75051898Smckusick fprintf(stderr, 75151898Smckusick "Making new ep fs=0x%x,0x%x\n", 75251898Smckusick fsb.f_fsid.val[0], 75351898Smckusick fsb.f_fsid.val[1]); 75451898Smckusick } else if (debug) 75551898Smckusick fprintf(stderr, 75651898Smckusick "Found ep fs=0x%x,0x%x\n", 75751898Smckusick fsb.f_fsid.val[0], 75851898Smckusick fsb.f_fsid.val[1]); 75938460Smckusick } 76051898Smckusick 76151898Smckusick /* 76251898Smckusick * Add dirpath to export mount point. 76351898Smckusick */ 76451898Smckusick dirp = add_expdir(&dirhead, cp, len); 76551898Smckusick dirplen = len; 76651898Smckusick } else { 76753150Smckusick getexp_err(ep, tgrp); 76851898Smckusick goto nextline; 76951898Smckusick } 77051898Smckusick *endcp = savedc; 77151898Smckusick } else { 77251898Smckusick savedc = *endcp; 77351898Smckusick *endcp = '\0'; 77451898Smckusick got_nondir = 1; 77566163Spendry if (ep == (struct exportlist *)NULL) { 77653150Smckusick getexp_err(ep, tgrp); 77751898Smckusick goto nextline; 77851898Smckusick } 77953150Smckusick 78053150Smckusick /* 78153150Smckusick * Get the host or netgroup. 78253150Smckusick */ 78353150Smckusick setnetgrent(cp); 78453150Smckusick netgrp = getnetgrent(&hst, &usr, &dom); 78553150Smckusick do { 78653150Smckusick if (has_host) { 78753150Smckusick grp->gr_next = get_grp(); 78853150Smckusick grp = grp->gr_next; 78953150Smckusick } 79053150Smckusick if (netgrp) { 79153150Smckusick if (get_host(hst, grp)) { 79253150Smckusick syslog(LOG_ERR, "Bad netgroup %s", cp); 79353150Smckusick getexp_err(ep, tgrp); 79468095Shibler endnetgrent(); 79553150Smckusick goto nextline; 79653150Smckusick } 79753150Smckusick } else if (get_host(cp, grp)) { 79853150Smckusick getexp_err(ep, tgrp); 79953150Smckusick goto nextline; 80053150Smckusick } 80153150Smckusick has_host = TRUE; 80253150Smckusick } while (netgrp && getnetgrent(&hst, &usr, &dom)); 80353150Smckusick endnetgrent(); 80451898Smckusick *endcp = savedc; 80538460Smckusick } 80638460Smckusick cp = endcp; 80738460Smckusick nextfield(&cp, &endcp); 80845271Smckusick len = endcp - cp; 80938460Smckusick } 81051898Smckusick if (check_options(dirhead)) { 81153150Smckusick getexp_err(ep, tgrp); 81251898Smckusick goto nextline; 81351898Smckusick } 81451898Smckusick if (!has_host) { 81551898Smckusick grp->gr_type = GT_HOST; 81651667Smckusick if (debug) 81751667Smckusick fprintf(stderr,"Adding a default entry\n"); 81851667Smckusick /* add a default group and make the grp list NULL */ 81951667Smckusick hpe = (struct hostent *)malloc(sizeof(struct hostent)); 82066163Spendry if (hpe == (struct hostent *)NULL) 82151898Smckusick out_of_mem(); 82251898Smckusick hpe->h_name = "Default"; 82351667Smckusick hpe->h_addrtype = AF_INET; 82451667Smckusick hpe->h_length = sizeof (u_long); 82566163Spendry hpe->h_addr_list = (char **)NULL; 82651898Smckusick grp->gr_ptr.gt_hostent = hpe; 82753150Smckusick 82853150Smckusick /* 82953150Smckusick * Don't allow a network export coincide with a list of 83053150Smckusick * host(s) on the same line. 83153150Smckusick */ 83253150Smckusick } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 83353150Smckusick getexp_err(ep, tgrp); 83453150Smckusick goto nextline; 83551667Smckusick } 83653150Smckusick 83753150Smckusick /* 83853150Smckusick * Loop through hosts, pushing the exports into the kernel. 83953150Smckusick * After loop, tgrp points to the start of the list and 84053150Smckusick * grp points to the last entry in the list. 84153150Smckusick */ 84253150Smckusick grp = tgrp; 84353150Smckusick do { 84453150Smckusick if (do_mount(ep, grp, exflags, &anon, dirp, 84551898Smckusick dirplen, &fsb)) { 84653150Smckusick getexp_err(ep, tgrp); 84751898Smckusick goto nextline; 84853150Smckusick } 84953150Smckusick } while (grp->gr_next && (grp = grp->gr_next)); 85051898Smckusick 85151898Smckusick /* 85251898Smckusick * Success. Update the data structures. 85351898Smckusick */ 85451898Smckusick if (has_host) { 855*68645Smckusick hang_dirp(dirhead, tgrp, ep, opt_flags); 85651898Smckusick grp->gr_next = grphead; 85753150Smckusick grphead = tgrp; 85851898Smckusick } else { 85966163Spendry hang_dirp(dirhead, (struct grouplist *)NULL, ep, 860*68645Smckusick opt_flags); 86151898Smckusick free_grp(grp); 86251898Smckusick } 86366163Spendry dirhead = (struct dirlist *)NULL; 86451898Smckusick if ((ep->ex_flag & EX_LINKED) == 0) { 86551898Smckusick ep2 = exphead; 86651898Smckusick epp = &exphead; 86751898Smckusick 86851898Smckusick /* 86951898Smckusick * Insert in the list in alphabetical order. 87051898Smckusick */ 87151898Smckusick while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 87251898Smckusick epp = &ep2->ex_next; 87351898Smckusick ep2 = ep2->ex_next; 87451898Smckusick } 87551898Smckusick if (ep2) 87651898Smckusick ep->ex_next = ep2; 87751898Smckusick *epp = ep; 87851898Smckusick ep->ex_flag |= EX_LINKED; 87951898Smckusick } 88051898Smckusick nextline: 88151898Smckusick if (dirhead) { 88251898Smckusick free_dir(dirhead); 88366163Spendry dirhead = (struct dirlist *)NULL; 88451898Smckusick } 88551898Smckusick } 88651898Smckusick fclose(exp_file); 88751898Smckusick } 88851898Smckusick 88951898Smckusick /* 89051898Smckusick * Allocate an export list element 89151898Smckusick */ 89251898Smckusick struct exportlist * 89351898Smckusick get_exp() 89451898Smckusick { 89566163Spendry struct exportlist *ep; 89651898Smckusick 89751898Smckusick ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 89866163Spendry if (ep == (struct exportlist *)NULL) 89951898Smckusick out_of_mem(); 90051898Smckusick bzero((caddr_t)ep, sizeof (struct exportlist)); 90151898Smckusick return (ep); 90251898Smckusick } 90351898Smckusick 90451898Smckusick /* 90551898Smckusick * Allocate a group list element 90651898Smckusick */ 90751898Smckusick struct grouplist * 90851898Smckusick get_grp() 90951898Smckusick { 91066163Spendry struct grouplist *gp; 91151898Smckusick 91251898Smckusick gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 91366163Spendry if (gp == (struct grouplist *)NULL) 91451898Smckusick out_of_mem(); 91551898Smckusick bzero((caddr_t)gp, sizeof (struct grouplist)); 91651898Smckusick return (gp); 91751898Smckusick } 91851898Smckusick 91951898Smckusick /* 92051898Smckusick * Clean up upon an error in get_exportlist(). 92151898Smckusick */ 92251898Smckusick void 92351898Smckusick getexp_err(ep, grp) 92451898Smckusick struct exportlist *ep; 92551898Smckusick struct grouplist *grp; 92651898Smckusick { 92753150Smckusick struct grouplist *tgrp; 92851898Smckusick 92951898Smckusick syslog(LOG_ERR, "Bad exports list line %s", line); 93059017Smckusick if (ep && (ep->ex_flag & EX_LINKED) == 0) 93151898Smckusick free_exp(ep); 93253150Smckusick while (grp) { 93353150Smckusick tgrp = grp; 93453150Smckusick grp = grp->gr_next; 93553150Smckusick free_grp(tgrp); 93653150Smckusick } 93751898Smckusick } 93851898Smckusick 93951898Smckusick /* 94051898Smckusick * Search the export list for a matching fs. 94151898Smckusick */ 94251898Smckusick struct exportlist * 94351898Smckusick ex_search(fsid) 94452109Smckusick fsid_t *fsid; 94551898Smckusick { 94666163Spendry struct exportlist *ep; 94751898Smckusick 94851898Smckusick ep = exphead; 94951898Smckusick while (ep) { 95051898Smckusick if (ep->ex_fs.val[0] == fsid->val[0] && 95151898Smckusick ep->ex_fs.val[1] == fsid->val[1]) 95251898Smckusick return (ep); 95351898Smckusick ep = ep->ex_next; 95451898Smckusick } 95551898Smckusick return (ep); 95651898Smckusick } 95751898Smckusick 95851898Smckusick /* 95951898Smckusick * Add a directory path to the list. 96051898Smckusick */ 96151898Smckusick char * 96251898Smckusick add_expdir(dpp, cp, len) 96351898Smckusick struct dirlist **dpp; 96451898Smckusick char *cp; 96551898Smckusick int len; 96651898Smckusick { 96766163Spendry struct dirlist *dp; 96851898Smckusick 96951898Smckusick dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 97051898Smckusick dp->dp_left = *dpp; 97166163Spendry dp->dp_right = (struct dirlist *)NULL; 97251898Smckusick dp->dp_flag = 0; 97366163Spendry dp->dp_hosts = (struct hostlist *)NULL; 97451898Smckusick strcpy(dp->dp_dirp, cp); 97551898Smckusick *dpp = dp; 97651898Smckusick return (dp->dp_dirp); 97751898Smckusick } 97851898Smckusick 97951898Smckusick /* 98051898Smckusick * Hang the dir list element off the dirpath binary tree as required 98151898Smckusick * and update the entry for host. 98251898Smckusick */ 98351898Smckusick void 984*68645Smckusick hang_dirp(dp, grp, ep, flags) 98566163Spendry struct dirlist *dp; 98651898Smckusick struct grouplist *grp; 98751898Smckusick struct exportlist *ep; 988*68645Smckusick int flags; 98951898Smckusick { 99066163Spendry struct hostlist *hp; 99151898Smckusick struct dirlist *dp2; 99251898Smckusick 993*68645Smckusick if (flags & OP_ALLDIRS) { 99451898Smckusick if (ep->ex_defdir) 99551898Smckusick free((caddr_t)dp); 99651898Smckusick else 99751898Smckusick ep->ex_defdir = dp; 998*68645Smckusick if (grp == (struct grouplist *)NULL) { 99955292Smckusick ep->ex_defdir->dp_flag |= DP_DEFSET; 1000*68645Smckusick if (flags & OP_KERB) 1001*68645Smckusick ep->ex_defdir->dp_flag |= DP_KERB; 1002*68645Smckusick } else while (grp) { 100351898Smckusick hp = get_ht(); 1004*68645Smckusick if (flags & OP_KERB) 1005*68645Smckusick hp->ht_flag |= DP_KERB; 100651898Smckusick hp->ht_grp = grp; 100751898Smckusick hp->ht_next = ep->ex_defdir->dp_hosts; 100851898Smckusick ep->ex_defdir->dp_hosts = hp; 100955292Smckusick grp = grp->gr_next; 101055292Smckusick } 101151898Smckusick } else { 101253150Smckusick 101353150Smckusick /* 101453150Smckusick * Loop throught the directories adding them to the tree. 101553150Smckusick */ 101651898Smckusick while (dp) { 101751898Smckusick dp2 = dp->dp_left; 1018*68645Smckusick add_dlist(&ep->ex_dirl, dp, grp, flags); 101951898Smckusick dp = dp2; 102051898Smckusick } 102151898Smckusick } 102251898Smckusick } 102351898Smckusick 102451898Smckusick /* 102551898Smckusick * Traverse the binary tree either updating a node that is already there 102651898Smckusick * for the new directory or adding the new node. 102751898Smckusick */ 102851898Smckusick void 1029*68645Smckusick add_dlist(dpp, newdp, grp, flags) 103051898Smckusick struct dirlist **dpp; 103151898Smckusick struct dirlist *newdp; 103266163Spendry struct grouplist *grp; 1033*68645Smckusick int flags; 103451898Smckusick { 103566163Spendry struct dirlist *dp; 103666163Spendry struct hostlist *hp; 103751898Smckusick int cmp; 103851898Smckusick 103951898Smckusick dp = *dpp; 104051898Smckusick if (dp) { 104151898Smckusick cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 104251898Smckusick if (cmp > 0) { 1043*68645Smckusick add_dlist(&dp->dp_left, newdp, grp, flags); 104451898Smckusick return; 104551898Smckusick } else if (cmp < 0) { 1046*68645Smckusick add_dlist(&dp->dp_right, newdp, grp, flags); 104751898Smckusick return; 104851898Smckusick } else 104951898Smckusick free((caddr_t)newdp); 105051898Smckusick } else { 105151898Smckusick dp = newdp; 105266163Spendry dp->dp_left = (struct dirlist *)NULL; 105351898Smckusick *dpp = dp; 105451898Smckusick } 105553150Smckusick if (grp) { 105653150Smckusick 105753150Smckusick /* 105853150Smckusick * Hang all of the host(s) off of the directory point. 105953150Smckusick */ 106053150Smckusick do { 106153150Smckusick hp = get_ht(); 1062*68645Smckusick if (flags & OP_KERB) 1063*68645Smckusick hp->ht_flag |= DP_KERB; 106453150Smckusick hp->ht_grp = grp; 106553150Smckusick hp->ht_next = dp->dp_hosts; 106653150Smckusick dp->dp_hosts = hp; 106753150Smckusick grp = grp->gr_next; 106853150Smckusick } while (grp); 1069*68645Smckusick } else { 107051898Smckusick dp->dp_flag |= DP_DEFSET; 1071*68645Smckusick if (flags & OP_KERB) 1072*68645Smckusick dp->dp_flag |= DP_KERB; 1073*68645Smckusick } 107451898Smckusick } 107551898Smckusick 107651898Smckusick /* 107751898Smckusick * Search for a dirpath on the export point. 107851898Smckusick */ 107951898Smckusick struct dirlist * 108051898Smckusick dirp_search(dp, dirpath) 108166163Spendry struct dirlist *dp; 108251898Smckusick char *dirpath; 108351898Smckusick { 108466163Spendry int cmp; 108551898Smckusick 108651898Smckusick if (dp) { 108751898Smckusick cmp = strcmp(dp->dp_dirp, dirpath); 108851898Smckusick if (cmp > 0) 108951898Smckusick return (dirp_search(dp->dp_left, dirpath)); 109051898Smckusick else if (cmp < 0) 109151898Smckusick return (dirp_search(dp->dp_right, dirpath)); 109251898Smckusick else 109351898Smckusick return (dp); 109451898Smckusick } 109551898Smckusick return (dp); 109651898Smckusick } 109751898Smckusick 109851898Smckusick /* 109951898Smckusick * Scan for a host match in a directory tree. 110051898Smckusick */ 110166163Spendry int 1102*68645Smckusick chk_host(dp, saddr, defsetp, hostsetp) 110351898Smckusick struct dirlist *dp; 110451898Smckusick u_long saddr; 110551898Smckusick int *defsetp; 1106*68645Smckusick int *hostsetp; 110751898Smckusick { 110866163Spendry struct hostlist *hp; 110966163Spendry struct grouplist *grp; 111066163Spendry u_long **addrp; 111151898Smckusick 111251898Smckusick if (dp) { 111351898Smckusick if (dp->dp_flag & DP_DEFSET) 1114*68645Smckusick *defsetp = dp->dp_flag; 111551898Smckusick hp = dp->dp_hosts; 111651898Smckusick while (hp) { 111751898Smckusick grp = hp->ht_grp; 111851898Smckusick switch (grp->gr_type) { 111951898Smckusick case GT_HOST: 112051898Smckusick addrp = (u_long **) 112151898Smckusick grp->gr_ptr.gt_hostent->h_addr_list; 112251898Smckusick while (*addrp) { 1123*68645Smckusick if (**addrp == saddr) { 1124*68645Smckusick *hostsetp = (hp->ht_flag | DP_HOSTSET); 112551898Smckusick return (1); 1126*68645Smckusick } 112751898Smckusick addrp++; 112851898Smckusick } 112951898Smckusick break; 113051898Smckusick case GT_NET: 113151898Smckusick if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 1132*68645Smckusick grp->gr_ptr.gt_net.nt_net) { 1133*68645Smckusick *hostsetp = (hp->ht_flag | DP_HOSTSET); 113451898Smckusick return (1); 1135*68645Smckusick } 113651898Smckusick break; 113751898Smckusick }; 113851898Smckusick hp = hp->ht_next; 113951898Smckusick } 114051898Smckusick } 114151898Smckusick return (0); 114251898Smckusick } 114351898Smckusick 114451898Smckusick /* 114551898Smckusick * Scan tree for a host that matches the address. 114651898Smckusick */ 114766163Spendry int 114851898Smckusick scan_tree(dp, saddr) 114966163Spendry struct dirlist *dp; 115051898Smckusick u_long saddr; 115151898Smckusick { 1152*68645Smckusick int defset, hostset; 115351898Smckusick 115451898Smckusick if (dp) { 115551898Smckusick if (scan_tree(dp->dp_left, saddr)) 115651898Smckusick return (1); 1157*68645Smckusick if (chk_host(dp, saddr, &defset, &hostset)) 115851898Smckusick return (1); 115951898Smckusick if (scan_tree(dp->dp_right, saddr)) 116051898Smckusick return (1); 116151898Smckusick } 116251898Smckusick return (0); 116351898Smckusick } 116451898Smckusick 116551898Smckusick /* 116651898Smckusick * Traverse the dirlist tree and free it up. 116751898Smckusick */ 116851898Smckusick void 116951898Smckusick free_dir(dp) 117066163Spendry struct dirlist *dp; 117151898Smckusick { 117251898Smckusick 117351898Smckusick if (dp) { 117451898Smckusick free_dir(dp->dp_left); 117551898Smckusick free_dir(dp->dp_right); 117651898Smckusick free_host(dp->dp_hosts); 117751898Smckusick free((caddr_t)dp); 117851898Smckusick } 117951898Smckusick } 118051898Smckusick 118151898Smckusick /* 118251898Smckusick * Parse the option string and update fields. 118351898Smckusick * Option arguments may either be -<option>=<value> or 118451898Smckusick * -<option> <value> 118551898Smckusick */ 118666163Spendry int 118751898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 118851898Smckusick char **cpp, **endcpp; 118951898Smckusick struct exportlist *ep; 119051898Smckusick struct grouplist *grp; 119151898Smckusick int *has_hostp; 119251898Smckusick int *exflagsp; 119351898Smckusick struct ucred *cr; 119451898Smckusick { 119566163Spendry char *cpoptarg, *cpoptend; 119651898Smckusick char *cp, *endcp, *cpopt, savedc, savedc2; 119751898Smckusick int allflag, usedarg; 119851898Smckusick 119951898Smckusick cpopt = *cpp; 120051898Smckusick cpopt++; 120151898Smckusick cp = *endcpp; 120251898Smckusick savedc = *cp; 120351898Smckusick *cp = '\0'; 120451898Smckusick while (cpopt && *cpopt) { 120551898Smckusick allflag = 1; 120651898Smckusick usedarg = -2; 120751898Smckusick if (cpoptend = index(cpopt, ',')) { 120851898Smckusick *cpoptend++ = '\0'; 120951898Smckusick if (cpoptarg = index(cpopt, '=')) 121051898Smckusick *cpoptarg++ = '\0'; 121151898Smckusick } else { 121251898Smckusick if (cpoptarg = index(cpopt, '=')) 121351898Smckusick *cpoptarg++ = '\0'; 121451898Smckusick else { 121551898Smckusick *cp = savedc; 121651898Smckusick nextfield(&cp, &endcp); 121751898Smckusick **endcpp = '\0'; 121851898Smckusick if (endcp > cp && *cp != '-') { 121951898Smckusick cpoptarg = cp; 122051898Smckusick savedc2 = *endcp; 122151898Smckusick *endcp = '\0'; 122251898Smckusick usedarg = 0; 122351667Smckusick } 122451667Smckusick } 122551667Smckusick } 122651898Smckusick if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 122751898Smckusick *exflagsp |= MNT_EXRDONLY; 122851898Smckusick } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 122951898Smckusick !(allflag = strcmp(cpopt, "mapall")) || 123051898Smckusick !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 123151898Smckusick usedarg++; 123251898Smckusick parsecred(cpoptarg, cr); 123351898Smckusick if (allflag == 0) { 123451898Smckusick *exflagsp |= MNT_EXPORTANON; 123551898Smckusick opt_flags |= OP_MAPALL; 123651898Smckusick } else 123751898Smckusick opt_flags |= OP_MAPROOT; 123851898Smckusick } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 123951898Smckusick *exflagsp |= MNT_EXKERB; 124051898Smckusick opt_flags |= OP_KERB; 124153150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "mask") || 124253150Smckusick !strcmp(cpopt, "m"))) { 124351898Smckusick if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 124451898Smckusick syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 124551898Smckusick return (1); 124651898Smckusick } 124751898Smckusick usedarg++; 124851898Smckusick opt_flags |= OP_MASK; 124953150Smckusick } else if (cpoptarg && (!strcmp(cpopt, "network") || 125053150Smckusick !strcmp(cpopt, "n"))) { 125151898Smckusick if (grp->gr_type != GT_NULL) { 125251898Smckusick syslog(LOG_ERR, "Network/host conflict"); 125351898Smckusick return (1); 125451898Smckusick } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 125551898Smckusick syslog(LOG_ERR, "Bad net: %s", cpoptarg); 125651898Smckusick return (1); 125751898Smckusick } 125851898Smckusick grp->gr_type = GT_NET; 125951898Smckusick *has_hostp = 1; 126051898Smckusick usedarg++; 126151898Smckusick opt_flags |= OP_NET; 126251898Smckusick } else if (!strcmp(cpopt, "alldirs")) { 126351898Smckusick opt_flags |= OP_ALLDIRS; 126451898Smckusick #ifdef ISO 126551898Smckusick } else if (cpoptarg && !strcmp(cpopt, "iso")) { 126651898Smckusick if (get_isoaddr(cpoptarg, grp)) { 126751898Smckusick syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 126851898Smckusick return (1); 126951898Smckusick } 127051898Smckusick *has_hostp = 1; 127151898Smckusick usedarg++; 127251898Smckusick opt_flags |= OP_ISO; 127351898Smckusick #endif /* ISO */ 127451898Smckusick } else { 127551898Smckusick syslog(LOG_ERR, "Bad opt %s", cpopt); 127651898Smckusick return (1); 127751667Smckusick } 127851898Smckusick if (usedarg >= 0) { 127951898Smckusick *endcp = savedc2; 128051898Smckusick **endcpp = savedc; 128151898Smckusick if (usedarg > 0) { 128251898Smckusick *cpp = cp; 128351898Smckusick *endcpp = endcp; 128451898Smckusick } 128551898Smckusick return (0); 128651898Smckusick } 128751898Smckusick cpopt = cpoptend; 128851667Smckusick } 128951898Smckusick **endcpp = savedc; 129051898Smckusick return (0); 129151898Smckusick } 129251898Smckusick 129351898Smckusick /* 129451898Smckusick * Translate a character string to the corresponding list of network 129551898Smckusick * addresses for a hostname. 129651898Smckusick */ 129766163Spendry int 129851898Smckusick get_host(cp, grp) 129951898Smckusick char *cp; 130066163Spendry struct grouplist *grp; 130151898Smckusick { 130266163Spendry struct hostent *hp, *nhp; 130366163Spendry char **addrp, **naddrp; 130451898Smckusick struct hostent t_host; 130551898Smckusick int i; 130651898Smckusick u_long saddr; 130751898Smckusick char *aptr[2]; 130851898Smckusick 130951898Smckusick if (grp->gr_type != GT_NULL) 131051898Smckusick return (1); 131151898Smckusick if ((hp = gethostbyname(cp)) == NULL) { 131251898Smckusick if (isdigit(*cp)) { 131351898Smckusick saddr = inet_addr(cp); 131451898Smckusick if (saddr == -1) { 131568095Shibler syslog(LOG_ERR, "Inet_addr failed for %s", cp); 131651898Smckusick return (1); 131751898Smckusick } 131851898Smckusick if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 131951898Smckusick AF_INET)) == NULL) { 132051898Smckusick hp = &t_host; 132151898Smckusick hp->h_name = cp; 132251898Smckusick hp->h_addrtype = AF_INET; 132351898Smckusick hp->h_length = sizeof (u_long); 132451898Smckusick hp->h_addr_list = aptr; 132551898Smckusick aptr[0] = (char *)&saddr; 132666163Spendry aptr[1] = (char *)NULL; 132751898Smckusick } 132851898Smckusick } else { 132968095Shibler syslog(LOG_ERR, "Gethostbyname failed for %s", cp); 133051898Smckusick return (1); 133151898Smckusick } 133251898Smckusick } 133351898Smckusick grp->gr_type = GT_HOST; 133451898Smckusick nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 133551898Smckusick malloc(sizeof(struct hostent)); 133666163Spendry if (nhp == (struct hostent *)NULL) 133751898Smckusick out_of_mem(); 133851898Smckusick bcopy((caddr_t)hp, (caddr_t)nhp, 133951898Smckusick sizeof(struct hostent)); 134051898Smckusick i = strlen(hp->h_name)+1; 134151898Smckusick nhp->h_name = (char *)malloc(i); 134266163Spendry if (nhp->h_name == (char *)NULL) 134351898Smckusick out_of_mem(); 134451898Smckusick bcopy(hp->h_name, nhp->h_name, i); 134551898Smckusick addrp = hp->h_addr_list; 134651898Smckusick i = 1; 134751898Smckusick while (*addrp++) 134851898Smckusick i++; 134951898Smckusick naddrp = nhp->h_addr_list = (char **) 135051898Smckusick malloc(i*sizeof(char *)); 135166163Spendry if (naddrp == (char **)NULL) 135251898Smckusick out_of_mem(); 135351898Smckusick addrp = hp->h_addr_list; 135451898Smckusick while (*addrp) { 135551898Smckusick *naddrp = (char *) 135651898Smckusick malloc(hp->h_length); 135766163Spendry if (*naddrp == (char *)NULL) 135851898Smckusick out_of_mem(); 135951898Smckusick bcopy(*addrp, *naddrp, 136051898Smckusick hp->h_length); 136151898Smckusick addrp++; 136251898Smckusick naddrp++; 136351898Smckusick } 136466163Spendry *naddrp = (char *)NULL; 136553150Smckusick if (debug) 136653150Smckusick fprintf(stderr, "got host %s\n", hp->h_name); 136751898Smckusick return (0); 136851898Smckusick } 136951898Smckusick 137051898Smckusick /* 137151898Smckusick * Free up an exports list component 137251898Smckusick */ 137351898Smckusick void 137451898Smckusick free_exp(ep) 137566163Spendry struct exportlist *ep; 137651898Smckusick { 137751898Smckusick 137851898Smckusick if (ep->ex_defdir) { 137951898Smckusick free_host(ep->ex_defdir->dp_hosts); 138051898Smckusick free((caddr_t)ep->ex_defdir); 138151898Smckusick } 138251898Smckusick if (ep->ex_fsdir) 138351898Smckusick free(ep->ex_fsdir); 138451898Smckusick free_dir(ep->ex_dirl); 138551898Smckusick free((caddr_t)ep); 138651898Smckusick } 138751898Smckusick 138851898Smckusick /* 138951898Smckusick * Free hosts. 139051898Smckusick */ 139151898Smckusick void 139251898Smckusick free_host(hp) 139366163Spendry struct hostlist *hp; 139451898Smckusick { 139566163Spendry struct hostlist *hp2; 139651898Smckusick 139751898Smckusick while (hp) { 139851898Smckusick hp2 = hp; 139951898Smckusick hp = hp->ht_next; 140051898Smckusick free((caddr_t)hp2); 140151898Smckusick } 140251898Smckusick } 140351898Smckusick 140451898Smckusick struct hostlist * 140551898Smckusick get_ht() 140651898Smckusick { 140766163Spendry struct hostlist *hp; 140851898Smckusick 140951898Smckusick hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 141066163Spendry if (hp == (struct hostlist *)NULL) 141151898Smckusick out_of_mem(); 141266163Spendry hp->ht_next = (struct hostlist *)NULL; 1413*68645Smckusick hp->ht_flag = 0; 141451898Smckusick return (hp); 141551898Smckusick } 141651898Smckusick 141751898Smckusick #ifdef ISO 141851898Smckusick /* 141951898Smckusick * Translate an iso address. 142051898Smckusick */ 142151898Smckusick get_isoaddr(cp, grp) 142251898Smckusick char *cp; 142351898Smckusick struct grouplist *grp; 142451898Smckusick { 142551898Smckusick struct iso_addr *isop; 142651898Smckusick struct sockaddr_iso *isoaddr; 142751898Smckusick 142851898Smckusick if (grp->gr_type != GT_NULL) 142951898Smckusick return (1); 143051898Smckusick if ((isop = iso_addr(cp)) == NULL) { 143151898Smckusick syslog(LOG_ERR, 143251898Smckusick "iso_addr failed, ignored"); 143351898Smckusick return (1); 143451898Smckusick } 143551898Smckusick isoaddr = (struct sockaddr_iso *) 143651898Smckusick malloc(sizeof (struct sockaddr_iso)); 143766163Spendry if (isoaddr == (struct sockaddr_iso *)NULL) 143851898Smckusick out_of_mem(); 143951898Smckusick bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 144051898Smckusick bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 144151898Smckusick sizeof (struct iso_addr)); 144251898Smckusick isoaddr->siso_len = sizeof (struct sockaddr_iso); 144351898Smckusick isoaddr->siso_family = AF_ISO; 144451898Smckusick grp->gr_type = GT_ISO; 144551898Smckusick grp->gr_ptr.gt_isoaddr = isoaddr; 144651898Smckusick return (0); 144751898Smckusick } 144851898Smckusick #endif /* ISO */ 144951898Smckusick 145051898Smckusick /* 145151898Smckusick * Out of memory, fatal 145251898Smckusick */ 145351898Smckusick void 145451898Smckusick out_of_mem() 145551898Smckusick { 145651898Smckusick 145751898Smckusick syslog(LOG_ERR, "Out of memory"); 145851667Smckusick exit(2); 145951667Smckusick } 146051667Smckusick 146151898Smckusick /* 146251898Smckusick * Do the mount syscall with the update flag to push the export info into 146351898Smckusick * the kernel. 146451898Smckusick */ 146566163Spendry int 146651898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 146751667Smckusick struct exportlist *ep; 146851667Smckusick struct grouplist *grp; 146951898Smckusick int exflags; 147051667Smckusick struct ucred *anoncrp; 147151898Smckusick char *dirp; 147251898Smckusick int dirplen; 147351898Smckusick struct statfs *fsb; 147451667Smckusick { 147566163Spendry char *cp = (char *)NULL; 147666163Spendry u_long **addrp; 147751898Smckusick int done; 147866163Spendry char savedc = '\0'; 147951898Smckusick struct sockaddr_in sin, imask; 148065713Shibler union { 148165713Shibler struct ufs_args ua; 148265713Shibler struct iso_args ia; 148365713Shibler struct mfs_args ma; 148465713Shibler } args; 148551898Smckusick u_long net; 148651667Smckusick 148765713Shibler args.ua.fspec = 0; 148865713Shibler args.ua.export.ex_flags = exflags; 148965713Shibler args.ua.export.ex_anon = *anoncrp; 149055878Smckusick bzero((char *)&sin, sizeof(sin)); 149155878Smckusick bzero((char *)&imask, sizeof(imask)); 149251667Smckusick sin.sin_family = AF_INET; 149351667Smckusick sin.sin_len = sizeof(sin); 149451898Smckusick imask.sin_family = AF_INET; 149551898Smckusick imask.sin_len = sizeof(sin); 149651898Smckusick if (grp->gr_type == GT_HOST) 149751667Smckusick addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 149851898Smckusick else 149966163Spendry addrp = (u_long **)NULL; 150051667Smckusick done = FALSE; 150151898Smckusick while (!done) { 150251898Smckusick switch (grp->gr_type) { 150351898Smckusick case GT_HOST: 150464903Smckusick if (addrp) { 150551712Smckusick sin.sin_addr.s_addr = **addrp; 150665713Shibler args.ua.export.ex_addrlen = sizeof(sin); 150764903Smckusick } else 150865713Shibler args.ua.export.ex_addrlen = 0; 150965713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 151065713Shibler args.ua.export.ex_masklen = 0; 151151898Smckusick break; 151251898Smckusick case GT_NET: 151351898Smckusick if (grp->gr_ptr.gt_net.nt_mask) 151451898Smckusick imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 151551898Smckusick else { 151651898Smckusick net = ntohl(grp->gr_ptr.gt_net.nt_net); 151751898Smckusick if (IN_CLASSA(net)) 151851898Smckusick imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 151951898Smckusick else if (IN_CLASSB(net)) 152051898Smckusick imask.sin_addr.s_addr = 152151898Smckusick inet_addr("255.255.0.0"); 152251898Smckusick else 152351898Smckusick imask.sin_addr.s_addr = 152451898Smckusick inet_addr("255.255.255.0"); 152551898Smckusick grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 152651898Smckusick } 152751898Smckusick sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 152865713Shibler args.ua.export.ex_addr = (struct sockaddr *)&sin; 152965713Shibler args.ua.export.ex_addrlen = sizeof (sin); 153065713Shibler args.ua.export.ex_mask = (struct sockaddr *)&imask; 153165713Shibler args.ua.export.ex_masklen = sizeof (imask); 153251898Smckusick break; 153351667Smckusick #ifdef ISO 153451898Smckusick case GT_ISO: 153565713Shibler args.ua.export.ex_addr = 153665713Shibler (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 153765713Shibler args.ua.export.ex_addrlen = 153865713Shibler sizeof(struct sockaddr_iso); 153965713Shibler args.ua.export.ex_masklen = 0; 154051898Smckusick break; 154151667Smckusick #endif /* ISO */ 154251898Smckusick default: 154351667Smckusick syslog(LOG_ERR, "Bad grouptype"); 154451898Smckusick if (cp) 154551898Smckusick *cp = savedc; 154651898Smckusick return (1); 154751898Smckusick }; 154852109Smckusick 154952109Smckusick /* 155052109Smckusick * XXX: 155152109Smckusick * Maybe I should just use the fsb->f_mntonname path instead 155252109Smckusick * of looping back up the dirp to the mount point?? 155352109Smckusick * Also, needs to know how to export all types of local 1554*68645Smckusick * exportable file systems and not just "ufs". 155552109Smckusick */ 1556*68645Smckusick while (mount(fsb->f_fstypename, dirp, 155752109Smckusick fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 155851898Smckusick if (cp) 155951898Smckusick *cp-- = savedc; 156051898Smckusick else 156151898Smckusick cp = dirp + dirplen - 1; 156251667Smckusick if (errno == EPERM) { 156351667Smckusick syslog(LOG_ERR, 156451898Smckusick "Can't change attributes for %s.\n", dirp); 156551898Smckusick return (1); 156651667Smckusick } 156751898Smckusick if (opt_flags & OP_ALLDIRS) { 156851898Smckusick syslog(LOG_ERR, "Not root dir"); 156951898Smckusick return (1); 157051898Smckusick } 157151667Smckusick /* back up over the last component */ 157251898Smckusick while (*cp == '/' && cp > dirp) 157351667Smckusick cp--; 157451898Smckusick while (*(cp - 1) != '/' && cp > dirp) 157551667Smckusick cp--; 157651898Smckusick if (cp == dirp) { 157751898Smckusick if (debug) 157851667Smckusick fprintf(stderr,"mnt unsucc\n"); 157951898Smckusick syslog(LOG_ERR, "Can't export %s", dirp); 158051898Smckusick return (1); 158151667Smckusick } 158251667Smckusick savedc = *cp; 158351667Smckusick *cp = '\0'; 158451667Smckusick } 158551898Smckusick if (addrp) { 158651667Smckusick ++addrp; 158766163Spendry if (*addrp == (u_long *)NULL) 158851667Smckusick done = TRUE; 158951898Smckusick } else 159051898Smckusick done = TRUE; 159151898Smckusick } 159251898Smckusick if (cp) 159351898Smckusick *cp = savedc; 159451898Smckusick return (0); 159551898Smckusick } 159651898Smckusick 159751898Smckusick /* 159851898Smckusick * Translate a net address. 159951898Smckusick */ 160066163Spendry int 160151898Smckusick get_net(cp, net, maskflg) 160251898Smckusick char *cp; 160351898Smckusick struct netmsk *net; 160451898Smckusick int maskflg; 160551898Smckusick { 160666163Spendry struct netent *np; 160766163Spendry long netaddr; 160851898Smckusick struct in_addr inetaddr, inetaddr2; 160951898Smckusick char *name; 161051898Smckusick 161151898Smckusick if (np = getnetbyname(cp)) 161251898Smckusick inetaddr = inet_makeaddr(np->n_net, 0); 161351898Smckusick else if (isdigit(*cp)) { 161451898Smckusick if ((netaddr = inet_network(cp)) == -1) 161551898Smckusick return (1); 161651898Smckusick inetaddr = inet_makeaddr(netaddr, 0); 161751898Smckusick /* 161851898Smckusick * Due to arbritrary subnet masks, you don't know how many 161951898Smckusick * bits to shift the address to make it into a network, 162051898Smckusick * however you do know how to make a network address into 162151898Smckusick * a host with host == 0 and then compare them. 162251898Smckusick * (What a pest) 162351898Smckusick */ 162451898Smckusick if (!maskflg) { 162551898Smckusick setnetent(0); 162651898Smckusick while (np = getnetent()) { 162751898Smckusick inetaddr2 = inet_makeaddr(np->n_net, 0); 162851898Smckusick if (inetaddr2.s_addr == inetaddr.s_addr) 162951898Smckusick break; 163051898Smckusick } 163151898Smckusick endnetent(); 163251667Smckusick } 163351898Smckusick } else 163451898Smckusick return (1); 163551898Smckusick if (maskflg) 163651898Smckusick net->nt_mask = inetaddr.s_addr; 163751898Smckusick else { 163851898Smckusick if (np) 163951898Smckusick name = np->n_name; 164051898Smckusick else 164151898Smckusick name = inet_ntoa(inetaddr); 164251898Smckusick net->nt_name = (char *)malloc(strlen(name) + 1); 164366163Spendry if (net->nt_name == (char *)NULL) 164451898Smckusick out_of_mem(); 164551898Smckusick strcpy(net->nt_name, name); 164651898Smckusick net->nt_net = inetaddr.s_addr; 164738460Smckusick } 164851898Smckusick return (0); 164938460Smckusick } 165038460Smckusick 165138460Smckusick /* 165238460Smckusick * Parse out the next white space separated field 165338460Smckusick */ 165451667Smckusick void 165538460Smckusick nextfield(cp, endcp) 165638460Smckusick char **cp; 165738460Smckusick char **endcp; 165838460Smckusick { 165966163Spendry char *p; 166038460Smckusick 166138460Smckusick p = *cp; 166238460Smckusick while (*p == ' ' || *p == '\t') 166338460Smckusick p++; 166451898Smckusick if (*p == '\n' || *p == '\0') 166538460Smckusick *cp = *endcp = p; 166651898Smckusick else { 166751898Smckusick *cp = p++; 166851898Smckusick while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 166951898Smckusick p++; 167051898Smckusick *endcp = p; 167138460Smckusick } 167238460Smckusick } 167339681Smckusick 167439681Smckusick /* 167551898Smckusick * Get an exports file line. Skip over blank lines and handle line 167651898Smckusick * continuations. 167739681Smckusick */ 167866163Spendry int 167951898Smckusick get_line() 168039681Smckusick { 168166163Spendry char *p, *cp; 168266163Spendry int len; 168351898Smckusick int totlen, cont_line; 168439681Smckusick 168551898Smckusick /* 168651898Smckusick * Loop around ignoring blank lines and getting all continuation lines. 168751898Smckusick */ 168851898Smckusick p = line; 168951898Smckusick totlen = 0; 169051898Smckusick do { 169151898Smckusick if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 169251898Smckusick return (0); 169351898Smckusick len = strlen(p); 169451898Smckusick cp = p + len - 1; 169551898Smckusick cont_line = 0; 169651898Smckusick while (cp >= p && 169751898Smckusick (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 169851898Smckusick if (*cp == '\\') 169951898Smckusick cont_line = 1; 170051898Smckusick cp--; 170151898Smckusick len--; 170251898Smckusick } 170351898Smckusick *++cp = '\0'; 170451898Smckusick if (len > 0) { 170551898Smckusick totlen += len; 170651898Smckusick if (totlen >= LINESIZ) { 170751898Smckusick syslog(LOG_ERR, "Exports line too long"); 170851898Smckusick exit(2); 170951898Smckusick } 171051898Smckusick p = cp; 171151898Smckusick } 171251898Smckusick } while (totlen == 0 || cont_line); 171351898Smckusick return (1); 171444015Smckusick } 171544015Smckusick 171651667Smckusick /* 171751667Smckusick * Parse a description of a credential. 171851667Smckusick */ 171966163Spendry void 172051667Smckusick parsecred(namelist, cr) 172151667Smckusick char *namelist; 172266163Spendry struct ucred *cr; 172351667Smckusick { 172466163Spendry char *name; 172566163Spendry int cnt; 172651667Smckusick char *names; 172751667Smckusick struct passwd *pw; 172851667Smckusick struct group *gr; 172951667Smckusick int ngroups, groups[NGROUPS + 1]; 173051667Smckusick 173151667Smckusick /* 173251667Smckusick * Set up the unpriviledged user. 173351667Smckusick */ 173451667Smckusick cr->cr_ref = 1; 173551667Smckusick cr->cr_uid = -2; 173651667Smckusick cr->cr_groups[0] = -2; 173751667Smckusick cr->cr_ngroups = 1; 173851667Smckusick /* 173951667Smckusick * Get the user's password table entry. 174051667Smckusick */ 174151667Smckusick names = strsep(&namelist, " \t\n"); 174251667Smckusick name = strsep(&names, ":"); 174351667Smckusick if (isdigit(*name) || *name == '-') 174451667Smckusick pw = getpwuid(atoi(name)); 174551667Smckusick else 174651667Smckusick pw = getpwnam(name); 174751667Smckusick /* 174851667Smckusick * Credentials specified as those of a user. 174951667Smckusick */ 175051667Smckusick if (names == NULL) { 175151667Smckusick if (pw == NULL) { 175266163Spendry syslog(LOG_ERR, "Unknown user: %s", name); 175351667Smckusick return; 175451667Smckusick } 175551667Smckusick cr->cr_uid = pw->pw_uid; 175651667Smckusick ngroups = NGROUPS + 1; 175751667Smckusick if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 175866163Spendry syslog(LOG_ERR, "Too many groups"); 175951667Smckusick /* 176051667Smckusick * Convert from int's to gid_t's and compress out duplicate 176151667Smckusick */ 176251667Smckusick cr->cr_ngroups = ngroups - 1; 176351667Smckusick cr->cr_groups[0] = groups[0]; 176451667Smckusick for (cnt = 2; cnt < ngroups; cnt++) 176551667Smckusick cr->cr_groups[cnt - 1] = groups[cnt]; 176651667Smckusick return; 176751667Smckusick } 176851667Smckusick /* 176951667Smckusick * Explicit credential specified as a colon separated list: 177051667Smckusick * uid:gid:gid:... 177151667Smckusick */ 177251667Smckusick if (pw != NULL) 177351667Smckusick cr->cr_uid = pw->pw_uid; 177451667Smckusick else if (isdigit(*name) || *name == '-') 177551667Smckusick cr->cr_uid = atoi(name); 177651667Smckusick else { 177766163Spendry syslog(LOG_ERR, "Unknown user: %s", name); 177851667Smckusick return; 177951667Smckusick } 178051667Smckusick cr->cr_ngroups = 0; 178151667Smckusick while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 178251667Smckusick name = strsep(&names, ":"); 178351667Smckusick if (isdigit(*name) || *name == '-') { 178451667Smckusick cr->cr_groups[cr->cr_ngroups++] = atoi(name); 178551667Smckusick } else { 178651667Smckusick if ((gr = getgrnam(name)) == NULL) { 178766163Spendry syslog(LOG_ERR, "Unknown group: %s", name); 178851667Smckusick continue; 178951667Smckusick } 179051667Smckusick cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 179151667Smckusick } 179251667Smckusick } 179351667Smckusick if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 179466163Spendry syslog(LOG_ERR, "Too many groups"); 179551667Smckusick } 179651667Smckusick 179744015Smckusick #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 179844015Smckusick /* 179944015Smckusick * Routines that maintain the remote mounttab 180044015Smckusick */ 180151667Smckusick void 180251667Smckusick get_mountlist() 180344015Smckusick { 180466163Spendry struct mountlist *mlp, **mlpp; 180566163Spendry char *eos, *dirp; 180644015Smckusick int len; 180744015Smckusick char str[STRSIZ]; 180844015Smckusick FILE *mlfile; 180944015Smckusick 181051712Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 181151667Smckusick syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 181244015Smckusick return; 181344015Smckusick } 181444015Smckusick mlpp = &mlhead; 181544015Smckusick while (fgets(str, STRSIZ, mlfile) != NULL) { 181644015Smckusick if ((dirp = index(str, '\t')) == NULL && 181744015Smckusick (dirp = index(str, ' ')) == NULL) 181844015Smckusick continue; 181944015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 182044015Smckusick len = dirp-str; 182144015Smckusick if (len > RPCMNT_NAMELEN) 182244015Smckusick len = RPCMNT_NAMELEN; 182344015Smckusick bcopy(str, mlp->ml_host, len); 182444015Smckusick mlp->ml_host[len] = '\0'; 182544015Smckusick while (*dirp == '\t' || *dirp == ' ') 182644015Smckusick dirp++; 182744015Smckusick if ((eos = index(dirp, '\t')) == NULL && 182844015Smckusick (eos = index(dirp, ' ')) == NULL && 182944015Smckusick (eos = index(dirp, '\n')) == NULL) 183044015Smckusick len = strlen(dirp); 183144015Smckusick else 183244015Smckusick len = eos-dirp; 183344015Smckusick if (len > RPCMNT_PATHLEN) 183444015Smckusick len = RPCMNT_PATHLEN; 183544015Smckusick bcopy(dirp, mlp->ml_dirp, len); 183644015Smckusick mlp->ml_dirp[len] = '\0'; 183766163Spendry mlp->ml_next = (struct mountlist *)NULL; 183844015Smckusick *mlpp = mlp; 183944015Smckusick mlpp = &mlp->ml_next; 184044015Smckusick } 184144015Smckusick fclose(mlfile); 184244015Smckusick } 184344015Smckusick 184451667Smckusick void 184551667Smckusick del_mlist(hostp, dirp) 184666163Spendry char *hostp, *dirp; 184744015Smckusick { 184866163Spendry struct mountlist *mlp, **mlpp; 184951712Smckusick struct mountlist *mlp2; 185044015Smckusick FILE *mlfile; 185144015Smckusick int fnd = 0; 185244015Smckusick 185344015Smckusick mlpp = &mlhead; 185444015Smckusick mlp = mlhead; 185544015Smckusick while (mlp) { 185644015Smckusick if (!strcmp(mlp->ml_host, hostp) && 185744015Smckusick (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 185844015Smckusick fnd = 1; 185951712Smckusick mlp2 = mlp; 186051712Smckusick *mlpp = mlp = mlp->ml_next; 186151712Smckusick free((caddr_t)mlp2); 186251712Smckusick } else { 186351712Smckusick mlpp = &mlp->ml_next; 186451712Smckusick mlp = mlp->ml_next; 186539681Smckusick } 186639681Smckusick } 186744015Smckusick if (fnd) { 186844015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 186951898Smckusick syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 187044015Smckusick return; 187144015Smckusick } 187244015Smckusick mlp = mlhead; 187344015Smckusick while (mlp) { 187444015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 187544015Smckusick mlp = mlp->ml_next; 187644015Smckusick } 187744015Smckusick fclose(mlfile); 187844015Smckusick } 187939681Smckusick } 188044015Smckusick 188151667Smckusick void 188251667Smckusick add_mlist(hostp, dirp) 188366163Spendry char *hostp, *dirp; 188444015Smckusick { 188566163Spendry struct mountlist *mlp, **mlpp; 188644015Smckusick FILE *mlfile; 188744015Smckusick 188844015Smckusick mlpp = &mlhead; 188944015Smckusick mlp = mlhead; 189044015Smckusick while (mlp) { 189144015Smckusick if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 189244015Smckusick return; 189344015Smckusick mlpp = &mlp->ml_next; 189444015Smckusick mlp = mlp->ml_next; 189544015Smckusick } 189644015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 189744015Smckusick strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 189844015Smckusick mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 189944015Smckusick strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 190044015Smckusick mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 190166163Spendry mlp->ml_next = (struct mountlist *)NULL; 190244015Smckusick *mlpp = mlp; 190344015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 190451898Smckusick syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 190544015Smckusick return; 190644015Smckusick } 190744015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 190844015Smckusick fclose(mlfile); 190944015Smckusick } 191044015Smckusick 191144015Smckusick /* 191244015Smckusick * This function is called via. SIGTERM when the system is going down. 191344015Smckusick * It sends a broadcast RPCMNT_UMNTALL. 191444015Smckusick */ 191546709Sbostic void 191644015Smckusick send_umntall() 191744015Smckusick { 191844015Smckusick (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 191944015Smckusick xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 192051667Smckusick exit(0); 192144015Smckusick } 192244015Smckusick 192366163Spendry int 192444015Smckusick umntall_each(resultsp, raddr) 192544015Smckusick caddr_t resultsp; 192644015Smckusick struct sockaddr_in *raddr; 192744015Smckusick { 192844015Smckusick return (1); 192944015Smckusick } 193044015Smckusick 193144015Smckusick /* 193251667Smckusick * Free up a group list. 193351667Smckusick */ 193451667Smckusick void 193551667Smckusick free_grp(grp) 193666163Spendry struct grouplist *grp; 193751667Smckusick { 193866163Spendry char **addrp; 193951667Smckusick 194051898Smckusick if (grp->gr_type == GT_HOST) { 194151712Smckusick if (grp->gr_ptr.gt_hostent->h_name) { 194251712Smckusick addrp = grp->gr_ptr.gt_hostent->h_addr_list; 194351712Smckusick while (addrp && *addrp) 194451712Smckusick free(*addrp++); 194551712Smckusick free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 194651712Smckusick free(grp->gr_ptr.gt_hostent->h_name); 194751712Smckusick } 194851667Smckusick free((caddr_t)grp->gr_ptr.gt_hostent); 194951898Smckusick } else if (grp->gr_type == GT_NET) { 195051898Smckusick if (grp->gr_ptr.gt_net.nt_name) 195151898Smckusick free(grp->gr_ptr.gt_net.nt_name); 195251667Smckusick } 195351667Smckusick #ifdef ISO 195451898Smckusick else if (grp->gr_type == GT_ISO) 195551667Smckusick free((caddr_t)grp->gr_ptr.gt_isoaddr); 195651667Smckusick #endif 195751667Smckusick free((caddr_t)grp); 195851667Smckusick } 195951667Smckusick 196051711Smckusick #ifdef DEBUG 196151711Smckusick void 196251711Smckusick SYSLOG(int pri, const char *fmt, ...) 196351711Smckusick { 196451711Smckusick va_list ap; 196551711Smckusick 196651711Smckusick va_start(ap, fmt); 196751711Smckusick vfprintf(stderr, fmt, ap); 196851711Smckusick va_end(ap); 196951711Smckusick } 197051711Smckusick #endif /* DEBUG */ 197151898Smckusick 197251898Smckusick /* 197351898Smckusick * Check options for consistency. 197451898Smckusick */ 197566163Spendry int 197651898Smckusick check_options(dp) 197751898Smckusick struct dirlist *dp; 197851898Smckusick { 197951898Smckusick 198066163Spendry if (dp == (struct dirlist *)NULL) 198151898Smckusick return (1); 198251898Smckusick if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 198351898Smckusick (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 198451898Smckusick (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 198551898Smckusick syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 198651898Smckusick return (1); 198751898Smckusick } 198851898Smckusick if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 198951898Smckusick syslog(LOG_ERR, "-mask requires -net"); 199051898Smckusick return (1); 199151898Smckusick } 199251898Smckusick if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 199351898Smckusick syslog(LOG_ERR, "-net and -iso mutually exclusive"); 199451898Smckusick return (1); 199551898Smckusick } 199651898Smckusick if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 199751898Smckusick syslog(LOG_ERR, "-alldir has multiple directories"); 199851898Smckusick return (1); 199951898Smckusick } 200051898Smckusick return (0); 200151898Smckusick } 200265940Sbostic 200365940Sbostic /* 200465940Sbostic * Check an absolute directory path for any symbolic links. Return true 200565940Sbostic * if no symbolic links are found. 200665940Sbostic */ 200765940Sbostic int 200865940Sbostic check_dirpath(dirp) 200966163Spendry char *dirp; 201065940Sbostic { 201166163Spendry char *cp; 201265940Sbostic int ret = 1; 201365940Sbostic struct stat sb; 201465940Sbostic 201565940Sbostic cp = dirp + 1; 201665940Sbostic while (*cp && ret) { 201765940Sbostic if (*cp == '/') { 201865940Sbostic *cp = '\0'; 201967383Smkm if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 202065940Sbostic ret = 0; 202165940Sbostic *cp = '/'; 202265940Sbostic } 202365940Sbostic cp++; 202465940Sbostic } 202567383Smkm if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 202665940Sbostic ret = 0; 202765940Sbostic return (ret); 202865940Sbostic } 2029*68645Smckusick 2030*68645Smckusick /* 2031*68645Smckusick * Just translate an ascii string to an integer. 2032*68645Smckusick */ 2033*68645Smckusick int 2034*68645Smckusick get_num(cp) 2035*68645Smckusick register char *cp; 2036*68645Smckusick { 2037*68645Smckusick register int res = 0; 2038*68645Smckusick 2039*68645Smckusick while (*cp) { 2040*68645Smckusick if (*cp < '0' || *cp > '9') 2041*68645Smckusick return (-1); 2042*68645Smckusick res = res * 10 + (*cp++ - '0'); 2043*68645Smckusick } 2044*68645Smckusick return (res); 2045*68645Smckusick } 2046