138460Smckusick /* 238460Smckusick * Copyright (c) 1989 The Regents of the University of California. 338460Smckusick * 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 1238460Smckusick char copyright[] = 1338460Smckusick "@(#) Copyright (c) 1989 Regents of the University of California.\n\ 1438460Smckusick All rights reserved.\n"; 1538460Smckusick #endif not lint 1638460Smckusick 1738460Smckusick #ifndef lint 18*51898Smckusick static char sccsid[] = "@(#)mountd.c 5.19 (Berkeley) 12/12/91"; 1938460Smckusick #endif not lint 2038460Smckusick 2151667Smckusick #include <pwd.h> 2251667Smckusick #include <grp.h> 2351667Smckusick #include <unistd.h> 2451667Smckusick #include <stdlib.h> 2551667Smckusick #include <fcntl.h> 2638460Smckusick #include <sys/param.h> 2738460Smckusick #include <sys/ioctl.h> 2838460Smckusick #include <sys/stat.h> 2939681Smckusick #include <sys/file.h> 3051667Smckusick #include <sys/ucred.h> 3138460Smckusick #include <sys/mount.h> 3238460Smckusick #include <sys/socket.h> 3338460Smckusick #include <sys/errno.h> 3442038Sbostic #include <sys/signal.h> 3542038Sbostic #include <stdio.h> 3642038Sbostic #include <string.h> 3742038Sbostic #include <syslog.h> 3838460Smckusick #include <netdb.h> 3938460Smckusick #include <rpc/rpc.h> 4038460Smckusick #include <rpc/pmap_clnt.h> 4138460Smckusick #include <rpc/pmap_prot.h> 4251667Smckusick #ifdef ISO 4351667Smckusick #include <netiso/iso.h> 4451667Smckusick #endif 4538460Smckusick #include <nfs/rpcv2.h> 4638460Smckusick #include <nfs/nfsv2.h> 4739681Smckusick #include "pathnames.h" 4838460Smckusick 4938460Smckusick /* 5038460Smckusick * Structures for keeping the mount list and export list 5138460Smckusick */ 5238460Smckusick struct mountlist { 5344015Smckusick struct mountlist *ml_next; 5438460Smckusick char ml_host[RPCMNT_NAMELEN+1]; 5538460Smckusick char ml_dirp[RPCMNT_PATHLEN+1]; 5638460Smckusick }; 5738460Smckusick 58*51898Smckusick struct dirlist { 59*51898Smckusick struct dirlist *dp_left; 60*51898Smckusick struct dirlist *dp_right; 61*51898Smckusick int dp_flag; 62*51898Smckusick struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 63*51898Smckusick char dp_dirp[1]; /* Actually malloc'd to size of dir */ 64*51898Smckusick }; 65*51898Smckusick /* dp_flag bits */ 66*51898Smckusick #define DP_DEFSET 0x1 67*51898Smckusick 6838460Smckusick struct exportlist { 6938460Smckusick struct exportlist *ex_next; 70*51898Smckusick struct dirlist *ex_dirl; 71*51898Smckusick struct dirlist *ex_defdir; 72*51898Smckusick int ex_flag; 73*51898Smckusick fsid_t ex_fs; 74*51898Smckusick char *ex_fsdir; 7538460Smckusick }; 76*51898Smckusick /* ex_flag bits */ 77*51898Smckusick #define EX_DONEDEL 0x2 78*51898Smckusick #define EX_LINKED 0x4 7938460Smckusick 80*51898Smckusick struct netmsk { 81*51898Smckusick u_long nt_net; 82*51898Smckusick u_long nt_mask; 83*51898Smckusick char *nt_name; 84*51898Smckusick }; 85*51898Smckusick 8651667Smckusick union grouptypes { 8751667Smckusick struct hostent *gt_hostent; 88*51898Smckusick struct netmsk gt_net; 8951667Smckusick #ifdef ISO 9051667Smckusick struct sockaddr_iso *gt_isoaddr; 9151667Smckusick #endif 9251667Smckusick }; 9351667Smckusick 9438460Smckusick struct grouplist { 95*51898Smckusick int gr_type; 9651667Smckusick union grouptypes gr_ptr; 9738460Smckusick struct grouplist *gr_next; 9838460Smckusick }; 99*51898Smckusick /* Group types */ 100*51898Smckusick #define GT_NULL 0x0 101*51898Smckusick #define GT_HOST 0x1 102*51898Smckusick #define GT_NET 0x2 103*51898Smckusick #define GT_ISO 0x4 10438460Smckusick 105*51898Smckusick struct hostlist { 106*51898Smckusick struct grouplist *ht_grp; 107*51898Smckusick struct hostlist *ht_next; 10851667Smckusick }; 10951667Smckusick 11038460Smckusick /* Global defs */ 11146709Sbostic int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist(); 112*51898Smckusick void get_exportlist(), send_umntall(), nextfield(), out_of_mem(); 11351667Smckusick void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp(); 114*51898Smckusick void getexp_err(), hang_dirp(), add_dlist(), free_dir(), free_host(); 115*51898Smckusick struct exportlist *ex_search(), *get_exp(); 116*51898Smckusick struct grouplist *get_grp(); 117*51898Smckusick char *realpath(), *add_expdir(); 118*51898Smckusick struct in_addr inet_makeaddr(); 119*51898Smckusick char *inet_ntoa(); 120*51898Smckusick struct dirlist *dirp_search(); 121*51898Smckusick struct hostlist *get_ht(); 12251667Smckusick #ifdef ISO 12351667Smckusick struct iso_addr *iso_addr(); 12451667Smckusick #endif 125*51898Smckusick struct exportlist *exphead; 12644015Smckusick struct mountlist *mlhead; 127*51898Smckusick struct grouplist *grphead; 12838460Smckusick char exname[MAXPATHLEN]; 12951667Smckusick struct ucred def_anon = { 13051667Smckusick (u_short) 1, 13151667Smckusick (uid_t) -2, 13251667Smckusick 1, 13351667Smckusick (gid_t) -2, 13451667Smckusick }; 13544015Smckusick int root_only = 1; 136*51898Smckusick int opt_flags; 137*51898Smckusick /* Bits for above */ 138*51898Smckusick #define OP_MAPROOT 0x01 139*51898Smckusick #define OP_MAPALL 0x02 140*51898Smckusick #define OP_KERB 0x04 141*51898Smckusick #define OP_MASK 0x08 142*51898Smckusick #define OP_NET 0x10 143*51898Smckusick #define OP_ISO 0x20 144*51898Smckusick #define OP_ALLDIRS 0x40 145*51898Smckusick 14638460Smckusick extern int errno; 14738460Smckusick #ifdef DEBUG 14838460Smckusick int debug = 1; 14951711Smckusick void SYSLOG __P((int, const char *, ...)); 15051711Smckusick #define syslog SYSLOG 15138460Smckusick #else 15238460Smckusick int debug = 0; 15338460Smckusick #endif 15438460Smckusick 15538460Smckusick /* 15638460Smckusick * Mountd server for NFS mount protocol as described in: 15739681Smckusick * NFS: Network File System Protocol Specification, RFC1094, Appendix A 15844015Smckusick * The optional arguments are the exports file name 15939681Smckusick * default: _PATH_EXPORTS 16044015Smckusick * and "-n" to allow nonroot mount. 16138460Smckusick */ 16238460Smckusick main(argc, argv) 16338460Smckusick int argc; 16444015Smckusick char **argv; 16538460Smckusick { 16638460Smckusick SVCXPRT *transp; 16744015Smckusick int c; 16844015Smckusick extern int optind; 16944015Smckusick extern char *optarg; 17038460Smckusick 17144015Smckusick while ((c = getopt(argc, argv, "n")) != EOF) 17244015Smckusick switch (c) { 17344015Smckusick case 'n': 17444015Smckusick root_only = 0; 17544015Smckusick break; 17644015Smckusick default: 17744015Smckusick fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); 17844015Smckusick exit(1); 17944015Smckusick }; 18044015Smckusick argc -= optind; 18144015Smckusick argv += optind; 182*51898Smckusick grphead = (struct grouplist *)0; 183*51898Smckusick exphead = (struct exportlist *)0; 18444015Smckusick mlhead = (struct mountlist *)0; 18544015Smckusick if (argc == 1) { 18644015Smckusick strncpy(exname, *argv, MAXPATHLEN-1); 18744015Smckusick exname[MAXPATHLEN-1] = '\0'; 18844015Smckusick } else 18944015Smckusick strcpy(exname, _PATH_EXPORTS); 19044338Smckusick openlog("mountd:", LOG_PID, LOG_DAEMON); 19151667Smckusick if (debug) 19251667Smckusick fprintf(stderr,"Getting export list.\n"); 19344015Smckusick get_exportlist(); 19451667Smckusick if (debug) 19551667Smckusick fprintf(stderr,"Getting mount list.\n"); 19644015Smckusick get_mountlist(); 19751667Smckusick if (debug) 19851667Smckusick fprintf(stderr,"Here we go.\n"); 19938460Smckusick if (debug == 0) { 20044690Skarels daemon(0, 0); 20138460Smckusick signal(SIGINT, SIG_IGN); 20238460Smckusick signal(SIGQUIT, SIG_IGN); 20338460Smckusick } 20438460Smckusick signal(SIGHUP, get_exportlist); 20544015Smckusick signal(SIGTERM, send_umntall); 20640494Smckusick { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 20740494Smckusick if (pidfile != NULL) { 20840494Smckusick fprintf(pidfile, "%d\n", getpid()); 20940494Smckusick fclose(pidfile); 21040494Smckusick } 21140494Smckusick } 21238460Smckusick if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { 21338460Smckusick syslog(LOG_ERR, "Can't create socket"); 21438460Smckusick exit(1); 21538460Smckusick } 21638460Smckusick pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 21751667Smckusick if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 21851667Smckusick IPPROTO_UDP)) { 21938460Smckusick syslog(LOG_ERR, "Can't register mount"); 22038460Smckusick exit(1); 22138460Smckusick } 22238460Smckusick svc_run(); 22338460Smckusick syslog(LOG_ERR, "Mountd died"); 22444690Skarels exit(1); 22538460Smckusick } 22638460Smckusick 22738460Smckusick /* 22838460Smckusick * The mount rpc service 22938460Smckusick */ 23038460Smckusick mntsrv(rqstp, transp) 23138460Smckusick register struct svc_req *rqstp; 23238460Smckusick register SVCXPRT *transp; 23338460Smckusick { 23438460Smckusick register struct exportlist *ep; 235*51898Smckusick register struct dirlist *dp; 23638460Smckusick nfsv2fh_t nfh; 23738460Smckusick struct authunix_parms *ucr; 23838460Smckusick struct stat stb; 239*51898Smckusick struct statfs fsb; 24038460Smckusick struct hostent *hp; 24139681Smckusick u_long saddr; 24251667Smckusick char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; 243*51898Smckusick int bad = ENOENT, omask, defset; 24439681Smckusick uid_t uid = -2; 24538460Smckusick 24638460Smckusick /* Get authorization */ 24738460Smckusick switch (rqstp->rq_cred.oa_flavor) { 24838460Smckusick case AUTH_UNIX: 24938460Smckusick ucr = (struct authunix_parms *)rqstp->rq_clntcred; 25039681Smckusick uid = ucr->aup_uid; 25139681Smckusick break; 25238460Smckusick case AUTH_NULL: 25338460Smckusick default: 25439681Smckusick break; 25538460Smckusick } 25638460Smckusick 25739681Smckusick saddr = transp->xp_raddr.sin_addr.s_addr; 25839681Smckusick hp = (struct hostent *)0; 25938460Smckusick switch (rqstp->rq_proc) { 26039681Smckusick case NULLPROC: 26139681Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 26239681Smckusick syslog(LOG_ERR, "Can't send reply"); 26339681Smckusick return; 26438460Smckusick case RPCMNT_MOUNT: 26551667Smckusick if ((uid != 0 && root_only) || uid == -2) { 26639681Smckusick svcerr_weakauth(transp); 26739681Smckusick return; 26839681Smckusick } 26951667Smckusick if (!svc_getargs(transp, xdr_dir, rpcpath)) { 27038460Smckusick svcerr_decode(transp); 27138460Smckusick return; 27238460Smckusick } 27338460Smckusick 27451667Smckusick /* 27551667Smckusick * Get the real pathname and make sure it is a directory 27651667Smckusick * that exists. 27751667Smckusick */ 278*51898Smckusick if (realpath(rpcpath, dirpath) == 0 || 279*51898Smckusick stat(dirpath, &stb) < 0 || 280*51898Smckusick (stb.st_mode & S_IFMT) != S_IFDIR || 281*51898Smckusick statfs(dirpath, &fsb) < 0) { 28251667Smckusick chdir("/"); /* Just in case realpath doesn't */ 28351667Smckusick if (debug) 284*51898Smckusick fprintf(stderr, "stat failed on %s\n", dirpath); 28538460Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 28638460Smckusick syslog(LOG_ERR, "Can't send reply"); 28738460Smckusick return; 28838460Smckusick } 28938460Smckusick 29038460Smckusick /* Check in the exports list */ 29138460Smckusick omask = sigblock(sigmask(SIGHUP)); 292*51898Smckusick ep = ex_search(&fsb.f_fsid); 293*51898Smckusick defset = 0; 294*51898Smckusick if (ep && (chk_host(ep->ex_defdir, saddr, &defset) || 295*51898Smckusick ((dp = dirp_search(ep->ex_dirl, dirpath)) && 296*51898Smckusick chk_host(dp, saddr, &defset)) || 297*51898Smckusick (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 298*51898Smckusick scan_tree(ep->ex_dirl, saddr) == 0))) { 29951667Smckusick /* Get the file handle */ 30051667Smckusick bzero((caddr_t)&nfh, sizeof(nfh)); 30151667Smckusick if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { 30251667Smckusick bad = errno; 303*51898Smckusick syslog(LOG_ERR, "Can't get fh for %s", dirpath); 30451667Smckusick if (!svc_sendreply(transp, xdr_long, 30551667Smckusick (caddr_t)&bad)) 30651667Smckusick syslog(LOG_ERR, "Can't send reply"); 30751667Smckusick sigsetmask(omask); 30851667Smckusick return; 30951667Smckusick } 31051667Smckusick if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) 31138460Smckusick syslog(LOG_ERR, "Can't send reply"); 31251667Smckusick if (hp == NULL) 31351667Smckusick hp = gethostbyaddr((caddr_t)&saddr, 31451667Smckusick sizeof(saddr), AF_INET); 31551667Smckusick if (hp) 31651667Smckusick add_mlist(hp->h_name, dirpath); 31751667Smckusick else 31851667Smckusick add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 31951667Smckusick dirpath); 32051667Smckusick if (debug) 32151667Smckusick fprintf(stderr,"Mount successfull.\n"); 322*51898Smckusick } else { 323*51898Smckusick bad = EACCES; 324*51898Smckusick if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 325*51898Smckusick syslog(LOG_ERR, "Can't send reply"); 32638460Smckusick } 32751667Smckusick sigsetmask(omask); 32838460Smckusick return; 32938460Smckusick case RPCMNT_DUMP: 33038460Smckusick if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0)) 33138460Smckusick syslog(LOG_ERR, "Can't send reply"); 33238460Smckusick return; 33338460Smckusick case RPCMNT_UMOUNT: 33451667Smckusick if ((uid != 0 && root_only) || uid == -2) { 33539681Smckusick svcerr_weakauth(transp); 33639681Smckusick return; 33739681Smckusick } 33838460Smckusick if (!svc_getargs(transp, xdr_dir, dirpath)) { 33938460Smckusick svcerr_decode(transp); 34038460Smckusick return; 34138460Smckusick } 34238460Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 34338460Smckusick syslog(LOG_ERR, "Can't send reply"); 34444015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 34544015Smckusick if (hp) 34644015Smckusick del_mlist(hp->h_name, dirpath); 34751667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 34838460Smckusick return; 34938460Smckusick case RPCMNT_UMNTALL: 35051667Smckusick if ((uid != 0 && root_only) || uid == -2) { 35139681Smckusick svcerr_weakauth(transp); 35239681Smckusick return; 35339681Smckusick } 35438460Smckusick if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 35538460Smckusick syslog(LOG_ERR, "Can't send reply"); 35644015Smckusick hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 35744015Smckusick if (hp) 35844015Smckusick del_mlist(hp->h_name, (char *)0); 35951667Smckusick del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)0); 36038460Smckusick return; 36138460Smckusick case RPCMNT_EXPORT: 36238460Smckusick if (!svc_sendreply(transp, xdr_explist, (caddr_t)0)) 36338460Smckusick syslog(LOG_ERR, "Can't send reply"); 36438460Smckusick return; 36538460Smckusick default: 36638460Smckusick svcerr_noproc(transp); 36738460Smckusick return; 36838460Smckusick } 36938460Smckusick } 37038460Smckusick 37138460Smckusick /* 37238460Smckusick * Xdr conversion for a dirpath string 37338460Smckusick */ 37438460Smckusick xdr_dir(xdrsp, dirp) 37538460Smckusick XDR *xdrsp; 37638460Smckusick char *dirp; 37738460Smckusick { 37838460Smckusick return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 37938460Smckusick } 38038460Smckusick 38138460Smckusick /* 38238460Smckusick * Xdr routine to generate fhstatus 38338460Smckusick */ 38438460Smckusick xdr_fhs(xdrsp, nfh) 38538460Smckusick XDR *xdrsp; 38638460Smckusick nfsv2fh_t *nfh; 38738460Smckusick { 38838460Smckusick int ok = 0; 38938460Smckusick 39038460Smckusick if (!xdr_long(xdrsp, &ok)) 39138460Smckusick return (0); 39238460Smckusick return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); 39338460Smckusick } 39438460Smckusick 39538460Smckusick xdr_mlist(xdrsp, cp) 39638460Smckusick XDR *xdrsp; 39738460Smckusick caddr_t cp; 39838460Smckusick { 39944015Smckusick register struct mountlist *mlp; 40038460Smckusick int true = 1; 40138460Smckusick int false = 0; 40238460Smckusick char *strp; 40338460Smckusick 40444015Smckusick mlp = mlhead; 40544015Smckusick while (mlp) { 40644015Smckusick if (!xdr_bool(xdrsp, &true)) 40744015Smckusick return (0); 40844015Smckusick strp = &mlp->ml_host[0]; 40944015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 41044015Smckusick return (0); 41144015Smckusick strp = &mlp->ml_dirp[0]; 41244015Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 41344015Smckusick return (0); 41444015Smckusick mlp = mlp->ml_next; 41538460Smckusick } 41638460Smckusick if (!xdr_bool(xdrsp, &false)) 41738460Smckusick return (0); 41838460Smckusick return (1); 41938460Smckusick } 42038460Smckusick 42138460Smckusick /* 42238460Smckusick * Xdr conversion for export list 42338460Smckusick */ 42438460Smckusick xdr_explist(xdrsp, cp) 42538460Smckusick XDR *xdrsp; 42638460Smckusick caddr_t cp; 42738460Smckusick { 42838460Smckusick register struct exportlist *ep; 42938460Smckusick int false = 0; 43038460Smckusick int omask; 43138460Smckusick 43238460Smckusick omask = sigblock(sigmask(SIGHUP)); 433*51898Smckusick ep = exphead; 434*51898Smckusick while (ep) { 435*51898Smckusick if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir)) 43638460Smckusick goto errout; 43738460Smckusick ep = ep->ex_next; 43838460Smckusick } 43938460Smckusick sigsetmask(omask); 44038460Smckusick if (!xdr_bool(xdrsp, &false)) 44138460Smckusick return (0); 44238460Smckusick return (1); 44338460Smckusick errout: 44438460Smckusick sigsetmask(omask); 44538460Smckusick return (0); 44638460Smckusick } 44738460Smckusick 448*51898Smckusick /* 449*51898Smckusick * Called from xdr_explist() to traverse the tree and export the 450*51898Smckusick * directory paths. 451*51898Smckusick */ 452*51898Smckusick put_exlist(dp, xdrsp, adp) 453*51898Smckusick register struct dirlist *dp; 454*51898Smckusick XDR *xdrsp; 455*51898Smckusick struct dirlist *adp; 456*51898Smckusick { 457*51898Smckusick register struct grouplist *grp; 458*51898Smckusick register struct hostlist *hp; 459*51898Smckusick struct in_addr inaddr; 460*51898Smckusick int true = 1; 461*51898Smckusick int false = 0; 462*51898Smckusick int gotalldir = 0; 463*51898Smckusick char *strp; 464*51898Smckusick 465*51898Smckusick if (dp) { 466*51898Smckusick if (put_exlist(dp->dp_left, xdrsp, adp)) 467*51898Smckusick return (1); 468*51898Smckusick if (!xdr_bool(xdrsp, &true)) 469*51898Smckusick return (1); 470*51898Smckusick strp = dp->dp_dirp; 471*51898Smckusick if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 472*51898Smckusick return (1); 473*51898Smckusick if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) 474*51898Smckusick gotalldir = 1; 475*51898Smckusick if ((dp->dp_flag & DP_DEFSET) == 0 && 476*51898Smckusick (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 477*51898Smckusick hp = dp->dp_hosts; 478*51898Smckusick while (hp) { 479*51898Smckusick grp = hp->ht_grp; 480*51898Smckusick if (grp->gr_type == GT_HOST) { 481*51898Smckusick if (!xdr_bool(xdrsp, &true)) 482*51898Smckusick return (1); 483*51898Smckusick strp = grp->gr_ptr.gt_hostent->h_name; 484*51898Smckusick if (!xdr_string(xdrsp, &strp, 485*51898Smckusick RPCMNT_NAMELEN)) 486*51898Smckusick return (1); 487*51898Smckusick } else if (grp->gr_type == GT_NET) { 488*51898Smckusick if (!xdr_bool(xdrsp, &true)) 489*51898Smckusick return (1); 490*51898Smckusick strp = grp->gr_ptr.gt_net.nt_name; 491*51898Smckusick if (!xdr_string(xdrsp, &strp, 492*51898Smckusick RPCMNT_NAMELEN)) 493*51898Smckusick return (1); 494*51898Smckusick } 495*51898Smckusick hp = hp->ht_next; 496*51898Smckusick if (gotalldir && hp == (struct hostlist *)0) { 497*51898Smckusick hp = adp->dp_hosts; 498*51898Smckusick gotalldir = 0; 499*51898Smckusick } 500*51898Smckusick } 501*51898Smckusick } 502*51898Smckusick if (!xdr_bool(xdrsp, &false)) 503*51898Smckusick return (1); 504*51898Smckusick if (put_exlist(dp->dp_right, xdrsp, adp)) 505*51898Smckusick return (1); 506*51898Smckusick } 507*51898Smckusick return (0); 508*51898Smckusick } 509*51898Smckusick 51038460Smckusick #define LINESIZ 10240 51138460Smckusick char line[LINESIZ]; 512*51898Smckusick FILE *exp_file; 51338460Smckusick 51438460Smckusick /* 51538460Smckusick * Get the export list 51638460Smckusick */ 51746709Sbostic void 51838460Smckusick get_exportlist() 51938460Smckusick { 52038460Smckusick register struct exportlist *ep, *ep2; 521*51898Smckusick register struct grouplist *grp, *tgrp; 522*51898Smckusick struct exportlist **epp; 523*51898Smckusick struct dirlist *dirhead; 524*51898Smckusick struct stat sb; 525*51898Smckusick struct statfs fsb; 526*51898Smckusick struct hostent *hpe; 527*51898Smckusick struct ucred anon; 528*51898Smckusick char *cp, *endcp, *dirp; 52939681Smckusick char savedc; 530*51898Smckusick int len, has_host, exflags, got_nondir, dirplen; 53138460Smckusick 53238460Smckusick /* 53338460Smckusick * First, get rid of the old list 53438460Smckusick */ 535*51898Smckusick ep = exphead; 536*51898Smckusick while (ep) { 53738460Smckusick ep2 = ep; 53838460Smckusick ep = ep->ex_next; 53944015Smckusick free_exp(ep2); 54038460Smckusick } 541*51898Smckusick exphead = (struct exportlist *)0; 54238460Smckusick 543*51898Smckusick grp = grphead; 544*51898Smckusick while (grp) { 545*51898Smckusick tgrp = grp; 546*51898Smckusick grp = grp->gr_next; 547*51898Smckusick free_grp(tgrp); 54851667Smckusick } 549*51898Smckusick grphead = (struct grouplist *)0; 55051667Smckusick 55138460Smckusick /* 55238460Smckusick * Read in the exports file and build the list, calling 55351667Smckusick * mount() as we go along to push the export rules into the kernel. 55438460Smckusick */ 555*51898Smckusick if ((exp_file = fopen(exname, "r")) == NULL) { 55638460Smckusick syslog(LOG_ERR, "Can't open %s", exname); 55738460Smckusick exit(2); 55838460Smckusick } 559*51898Smckusick dirhead = (struct dirlist *)0; 560*51898Smckusick while (get_line()) { 56151667Smckusick if (debug) 56251667Smckusick fprintf(stderr,"Got line %s\n",line); 56338460Smckusick cp = line; 56438460Smckusick nextfield(&cp, &endcp); 56551667Smckusick if (*cp == '#') 56651667Smckusick goto nextline; 567*51898Smckusick 568*51898Smckusick /* 569*51898Smckusick * Set defaults. 570*51898Smckusick */ 571*51898Smckusick has_host = FALSE; 572*51898Smckusick anon = def_anon; 57351667Smckusick exflags = MNT_EXPORTED; 574*51898Smckusick got_nondir = 0; 575*51898Smckusick opt_flags = 0; 576*51898Smckusick ep = (struct exportlist *)0; 57744015Smckusick 57844015Smckusick /* 57944015Smckusick * Create new exports list entry 58044015Smckusick */ 58138460Smckusick len = endcp-cp; 582*51898Smckusick grp = get_grp(); 583*51898Smckusick while (len > 0) { 584*51898Smckusick if (len > RPCMNT_NAMELEN) { 585*51898Smckusick getexp_err(ep, grp); 586*51898Smckusick goto nextline; 58751667Smckusick } 58845271Smckusick if (*cp == '-') { 589*51898Smckusick if (ep == (struct exportlist *)0) { 590*51898Smckusick getexp_err(ep, grp); 591*51898Smckusick goto nextline; 592*51898Smckusick } 593*51898Smckusick if (debug) 594*51898Smckusick fprintf(stderr, "doing opt %s\n", cp); 595*51898Smckusick got_nondir = 1; 596*51898Smckusick if (do_opt(&cp, &endcp, ep, grp, &has_host, 597*51898Smckusick &exflags, &anon)) { 598*51898Smckusick getexp_err(ep, grp); 599*51898Smckusick goto nextline; 600*51898Smckusick } 601*51898Smckusick } else if (*cp == '/') { 602*51898Smckusick savedc = *endcp; 603*51898Smckusick *endcp = '\0'; 604*51898Smckusick if (stat(cp, &sb) >= 0 && 605*51898Smckusick (sb.st_mode & S_IFMT) == S_IFDIR && 606*51898Smckusick statfs(cp, &fsb) >= 0) { 607*51898Smckusick if (got_nondir) { 608*51898Smckusick syslog(LOG_ERR, "Dirs must be first"); 609*51898Smckusick getexp_err(ep, grp); 610*51898Smckusick goto nextline; 611*51898Smckusick } 612*51898Smckusick if (ep) { 613*51898Smckusick if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 614*51898Smckusick ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 615*51898Smckusick getexp_err(ep, grp); 616*51898Smckusick goto nextline; 617*51898Smckusick } 61851667Smckusick } else { 619*51898Smckusick /* 620*51898Smckusick * See if this directory is already 621*51898Smckusick * in the list. 622*51898Smckusick */ 623*51898Smckusick ep = ex_search(&fsb.f_fsid); 624*51898Smckusick if (ep == (struct exportlist *)0) { 625*51898Smckusick ep = get_exp(); 626*51898Smckusick ep->ex_fs = fsb.f_fsid; 627*51898Smckusick ep->ex_fsdir = (char *) 628*51898Smckusick malloc(strlen(fsb.f_mntonname) + 1); 629*51898Smckusick if (ep->ex_fsdir) 630*51898Smckusick strcpy(ep->ex_fsdir, 631*51898Smckusick fsb.f_mntonname); 632*51898Smckusick else 633*51898Smckusick out_of_mem(); 634*51898Smckusick if (debug) 635*51898Smckusick fprintf(stderr, 636*51898Smckusick "Making new ep fs=0x%x,0x%x\n", 637*51898Smckusick fsb.f_fsid.val[0], 638*51898Smckusick fsb.f_fsid.val[1]); 639*51898Smckusick } else if (debug) 640*51898Smckusick fprintf(stderr, 641*51898Smckusick "Found ep fs=0x%x,0x%x\n", 642*51898Smckusick fsb.f_fsid.val[0], 643*51898Smckusick fsb.f_fsid.val[1]); 64438460Smckusick } 645*51898Smckusick 646*51898Smckusick /* 647*51898Smckusick * Add dirpath to export mount point. 648*51898Smckusick */ 649*51898Smckusick dirp = add_expdir(&dirhead, cp, len); 650*51898Smckusick dirplen = len; 651*51898Smckusick } else { 652*51898Smckusick getexp_err(ep, grp); 653*51898Smckusick goto nextline; 654*51898Smckusick } 655*51898Smckusick *endcp = savedc; 656*51898Smckusick } else { 657*51898Smckusick savedc = *endcp; 658*51898Smckusick *endcp = '\0'; 659*51898Smckusick got_nondir = 1; 660*51898Smckusick if (ep == (struct exportlist *)0 || has_host) { 661*51898Smckusick getexp_err(ep, grp); 662*51898Smckusick goto nextline; 663*51898Smckusick } 664*51898Smckusick if (get_host(cp, grp)) { 665*51898Smckusick getexp_err(ep, grp); 666*51898Smckusick goto nextline; 667*51898Smckusick } 668*51898Smckusick has_host = TRUE; 669*51898Smckusick *endcp = savedc; 67038460Smckusick } 67138460Smckusick cp = endcp; 67238460Smckusick nextfield(&cp, &endcp); 67345271Smckusick len = endcp - cp; 67438460Smckusick } 675*51898Smckusick if (check_options(dirhead)) { 676*51898Smckusick getexp_err(ep, grp); 677*51898Smckusick goto nextline; 678*51898Smckusick } 679*51898Smckusick if (!has_host) { 680*51898Smckusick grp->gr_type = GT_HOST; 68151667Smckusick if (debug) 68251667Smckusick fprintf(stderr,"Adding a default entry\n"); 68351667Smckusick /* add a default group and make the grp list NULL */ 68451667Smckusick hpe = (struct hostent *)malloc(sizeof(struct hostent)); 685*51898Smckusick if (hpe == (struct hostent *)0) 686*51898Smckusick out_of_mem(); 687*51898Smckusick hpe->h_name = "Default"; 68851667Smckusick hpe->h_addrtype = AF_INET; 68951667Smckusick hpe->h_length = sizeof (u_long); 69051712Smckusick hpe->h_addr_list = (char **)0; 691*51898Smckusick grp->gr_ptr.gt_hostent = hpe; 69251667Smckusick } 693*51898Smckusick if (do_mount(ep, grp, exflags, &anon, dirp, 694*51898Smckusick dirplen, &fsb)) { 695*51898Smckusick getexp_err(ep, grp); 696*51898Smckusick goto nextline; 697*51898Smckusick } 698*51898Smckusick 699*51898Smckusick /* 700*51898Smckusick * Success. Update the data structures. 701*51898Smckusick */ 702*51898Smckusick if (has_host) { 703*51898Smckusick grp->gr_next = grphead; 704*51898Smckusick grphead = grp; 705*51898Smckusick hang_dirp(dirhead, grp, ep, (opt_flags & OP_ALLDIRS)); 706*51898Smckusick } else { 707*51898Smckusick hang_dirp(dirhead, (struct grouplist *)0, ep, 708*51898Smckusick (opt_flags & OP_ALLDIRS)); 709*51898Smckusick free_grp(grp); 710*51898Smckusick } 711*51898Smckusick dirhead = (struct dirlist *)0; 712*51898Smckusick if ((ep->ex_flag & EX_LINKED) == 0) { 713*51898Smckusick ep2 = exphead; 714*51898Smckusick epp = &exphead; 715*51898Smckusick 716*51898Smckusick /* 717*51898Smckusick * Insert in the list in alphabetical order. 718*51898Smckusick */ 719*51898Smckusick while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 720*51898Smckusick epp = &ep2->ex_next; 721*51898Smckusick ep2 = ep2->ex_next; 722*51898Smckusick } 723*51898Smckusick if (ep2) 724*51898Smckusick ep->ex_next = ep2; 725*51898Smckusick *epp = ep; 726*51898Smckusick ep->ex_flag |= EX_LINKED; 727*51898Smckusick } 728*51898Smckusick nextline: 729*51898Smckusick if (dirhead) { 730*51898Smckusick free_dir(dirhead); 731*51898Smckusick dirhead = (struct dirlist *)0; 732*51898Smckusick } 733*51898Smckusick } 734*51898Smckusick fclose(exp_file); 735*51898Smckusick } 736*51898Smckusick 737*51898Smckusick /* 738*51898Smckusick * Allocate an export list element 739*51898Smckusick */ 740*51898Smckusick struct exportlist * 741*51898Smckusick get_exp() 742*51898Smckusick { 743*51898Smckusick register struct exportlist *ep; 744*51898Smckusick 745*51898Smckusick ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 746*51898Smckusick if (ep == (struct exportlist *)0) 747*51898Smckusick out_of_mem(); 748*51898Smckusick bzero((caddr_t)ep, sizeof (struct exportlist)); 749*51898Smckusick return (ep); 750*51898Smckusick } 751*51898Smckusick 752*51898Smckusick /* 753*51898Smckusick * Allocate a group list element 754*51898Smckusick */ 755*51898Smckusick struct grouplist * 756*51898Smckusick get_grp() 757*51898Smckusick { 758*51898Smckusick register struct grouplist *gp; 759*51898Smckusick 760*51898Smckusick gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 761*51898Smckusick if (gp == (struct grouplist *)0) 762*51898Smckusick out_of_mem(); 763*51898Smckusick bzero((caddr_t)gp, sizeof (struct grouplist)); 764*51898Smckusick return (gp); 765*51898Smckusick } 766*51898Smckusick 767*51898Smckusick /* 768*51898Smckusick * Clean up upon an error in get_exportlist(). 769*51898Smckusick */ 770*51898Smckusick void 771*51898Smckusick getexp_err(ep, grp) 772*51898Smckusick struct exportlist *ep; 773*51898Smckusick struct grouplist *grp; 774*51898Smckusick { 775*51898Smckusick 776*51898Smckusick syslog(LOG_ERR, "Bad exports list line %s", line); 777*51898Smckusick if (ep && ep->ex_next == (struct exportlist *)0) 778*51898Smckusick free_exp(ep); 779*51898Smckusick if (grp && grp->gr_next == (struct grouplist *)0) 780*51898Smckusick free_grp(grp); 781*51898Smckusick } 782*51898Smckusick 783*51898Smckusick /* 784*51898Smckusick * Search the export list for a matching fs. 785*51898Smckusick */ 786*51898Smckusick struct exportlist * 787*51898Smckusick ex_search(fsid) 788*51898Smckusick quad *fsid; 789*51898Smckusick { 790*51898Smckusick register struct exportlist *ep; 791*51898Smckusick 792*51898Smckusick ep = exphead; 793*51898Smckusick while (ep) { 794*51898Smckusick if (ep->ex_fs.val[0] == fsid->val[0] && 795*51898Smckusick ep->ex_fs.val[1] == fsid->val[1]) 796*51898Smckusick return (ep); 797*51898Smckusick ep = ep->ex_next; 798*51898Smckusick } 799*51898Smckusick return (ep); 800*51898Smckusick } 801*51898Smckusick 802*51898Smckusick /* 803*51898Smckusick * Add a directory path to the list. 804*51898Smckusick */ 805*51898Smckusick char * 806*51898Smckusick add_expdir(dpp, cp, len) 807*51898Smckusick struct dirlist **dpp; 808*51898Smckusick char *cp; 809*51898Smckusick int len; 810*51898Smckusick { 811*51898Smckusick register struct dirlist *dp; 812*51898Smckusick 813*51898Smckusick dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 814*51898Smckusick dp->dp_left = *dpp; 815*51898Smckusick dp->dp_right = (struct dirlist *)0; 816*51898Smckusick dp->dp_flag = 0; 817*51898Smckusick dp->dp_hosts = (struct hostlist *)0; 818*51898Smckusick strcpy(dp->dp_dirp, cp); 819*51898Smckusick *dpp = dp; 820*51898Smckusick return (dp->dp_dirp); 821*51898Smckusick } 822*51898Smckusick 823*51898Smckusick /* 824*51898Smckusick * Hang the dir list element off the dirpath binary tree as required 825*51898Smckusick * and update the entry for host. 826*51898Smckusick */ 827*51898Smckusick void 828*51898Smckusick hang_dirp(dp, grp, ep, alldirs) 829*51898Smckusick register struct dirlist *dp; 830*51898Smckusick struct grouplist *grp; 831*51898Smckusick struct exportlist *ep; 832*51898Smckusick int alldirs; 833*51898Smckusick { 834*51898Smckusick register struct hostlist *hp; 835*51898Smckusick struct dirlist *dp2; 836*51898Smckusick 837*51898Smckusick if (alldirs) { 838*51898Smckusick if (ep->ex_defdir) 839*51898Smckusick free((caddr_t)dp); 840*51898Smckusick else 841*51898Smckusick ep->ex_defdir = dp; 842*51898Smckusick if (grp) { 843*51898Smckusick hp = get_ht(); 844*51898Smckusick hp->ht_grp = grp; 845*51898Smckusick hp->ht_next = ep->ex_defdir->dp_hosts; 846*51898Smckusick ep->ex_defdir->dp_hosts = hp; 847*51898Smckusick } else 848*51898Smckusick ep->ex_defdir->dp_flag |= DP_DEFSET; 849*51898Smckusick } else { 850*51898Smckusick while (dp) { 851*51898Smckusick if (grp) { 852*51898Smckusick hp = get_ht(); 853*51898Smckusick hp->ht_grp = grp; 854*51898Smckusick } else 855*51898Smckusick hp = (struct hostlist *)0; 856*51898Smckusick dp2 = dp->dp_left; 857*51898Smckusick add_dlist(&ep->ex_dirl, dp, hp); 858*51898Smckusick dp = dp2; 859*51898Smckusick } 860*51898Smckusick } 861*51898Smckusick } 862*51898Smckusick 863*51898Smckusick /* 864*51898Smckusick * Traverse the binary tree either updating a node that is already there 865*51898Smckusick * for the new directory or adding the new node. 866*51898Smckusick */ 867*51898Smckusick void 868*51898Smckusick add_dlist(dpp, newdp, hp) 869*51898Smckusick struct dirlist **dpp; 870*51898Smckusick struct dirlist *newdp; 871*51898Smckusick struct hostlist *hp; 872*51898Smckusick { 873*51898Smckusick register struct dirlist *dp; 874*51898Smckusick int cmp; 875*51898Smckusick 876*51898Smckusick dp = *dpp; 877*51898Smckusick if (dp) { 878*51898Smckusick cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 879*51898Smckusick if (cmp > 0) { 880*51898Smckusick add_dlist(&dp->dp_left, newdp, hp); 881*51898Smckusick return; 882*51898Smckusick } else if (cmp < 0) { 883*51898Smckusick add_dlist(&dp->dp_right, newdp, hp); 884*51898Smckusick return; 885*51898Smckusick } else 886*51898Smckusick free((caddr_t)newdp); 887*51898Smckusick } else { 888*51898Smckusick dp = newdp; 889*51898Smckusick dp->dp_left = (struct dirlist *)0; 890*51898Smckusick *dpp = dp; 891*51898Smckusick } 892*51898Smckusick if (hp) { 893*51898Smckusick hp->ht_next = dp->dp_hosts; 894*51898Smckusick dp->dp_hosts = hp; 895*51898Smckusick } else 896*51898Smckusick dp->dp_flag |= DP_DEFSET; 897*51898Smckusick } 898*51898Smckusick 899*51898Smckusick /* 900*51898Smckusick * Search for a dirpath on the export point. 901*51898Smckusick */ 902*51898Smckusick struct dirlist * 903*51898Smckusick dirp_search(dp, dirpath) 904*51898Smckusick register struct dirlist *dp; 905*51898Smckusick char *dirpath; 906*51898Smckusick { 907*51898Smckusick register int cmp; 908*51898Smckusick 909*51898Smckusick if (dp) { 910*51898Smckusick cmp = strcmp(dp->dp_dirp, dirpath); 911*51898Smckusick if (cmp > 0) 912*51898Smckusick return (dirp_search(dp->dp_left, dirpath)); 913*51898Smckusick else if (cmp < 0) 914*51898Smckusick return (dirp_search(dp->dp_right, dirpath)); 915*51898Smckusick else 916*51898Smckusick return (dp); 917*51898Smckusick } 918*51898Smckusick return (dp); 919*51898Smckusick } 920*51898Smckusick 921*51898Smckusick /* 922*51898Smckusick * Scan for a host match in a directory tree. 923*51898Smckusick */ 924*51898Smckusick chk_host(dp, saddr, defsetp) 925*51898Smckusick struct dirlist *dp; 926*51898Smckusick u_long saddr; 927*51898Smckusick int *defsetp; 928*51898Smckusick { 929*51898Smckusick register struct hostlist *hp; 930*51898Smckusick register struct grouplist *grp; 931*51898Smckusick register u_long **addrp; 932*51898Smckusick 933*51898Smckusick if (dp) { 934*51898Smckusick if (dp->dp_flag & DP_DEFSET) 935*51898Smckusick *defsetp = 1; 936*51898Smckusick hp = dp->dp_hosts; 937*51898Smckusick while (hp) { 938*51898Smckusick grp = hp->ht_grp; 939*51898Smckusick switch (grp->gr_type) { 940*51898Smckusick case GT_HOST: 941*51898Smckusick addrp = (u_long **) 942*51898Smckusick grp->gr_ptr.gt_hostent->h_addr_list; 943*51898Smckusick while (*addrp) { 944*51898Smckusick if (**addrp == saddr) 945*51898Smckusick return (1); 946*51898Smckusick addrp++; 947*51898Smckusick } 948*51898Smckusick break; 949*51898Smckusick case GT_NET: 950*51898Smckusick if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 951*51898Smckusick grp->gr_ptr.gt_net.nt_net) 952*51898Smckusick return (1); 953*51898Smckusick break; 954*51898Smckusick }; 955*51898Smckusick hp = hp->ht_next; 956*51898Smckusick } 957*51898Smckusick } 958*51898Smckusick return (0); 959*51898Smckusick } 960*51898Smckusick 961*51898Smckusick /* 962*51898Smckusick * Scan tree for a host that matches the address. 963*51898Smckusick */ 964*51898Smckusick scan_tree(dp, saddr) 965*51898Smckusick register struct dirlist *dp; 966*51898Smckusick u_long saddr; 967*51898Smckusick { 968*51898Smckusick int defset; 969*51898Smckusick 970*51898Smckusick if (dp) { 971*51898Smckusick if (scan_tree(dp->dp_left, saddr)) 972*51898Smckusick return (1); 973*51898Smckusick if (chk_host(dp, saddr, &defset)) 974*51898Smckusick return (1); 975*51898Smckusick if (scan_tree(dp->dp_right, saddr)) 976*51898Smckusick return (1); 977*51898Smckusick } 978*51898Smckusick return (0); 979*51898Smckusick } 980*51898Smckusick 981*51898Smckusick /* 982*51898Smckusick * Traverse the dirlist tree and free it up. 983*51898Smckusick */ 984*51898Smckusick void 985*51898Smckusick free_dir(dp) 986*51898Smckusick register struct dirlist *dp; 987*51898Smckusick { 988*51898Smckusick 989*51898Smckusick if (dp) { 990*51898Smckusick free_dir(dp->dp_left); 991*51898Smckusick free_dir(dp->dp_right); 992*51898Smckusick free_host(dp->dp_hosts); 993*51898Smckusick free((caddr_t)dp); 994*51898Smckusick } 995*51898Smckusick } 996*51898Smckusick 997*51898Smckusick /* 998*51898Smckusick * Parse the option string and update fields. 999*51898Smckusick * Option arguments may either be -<option>=<value> or 1000*51898Smckusick * -<option> <value> 1001*51898Smckusick */ 1002*51898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1003*51898Smckusick char **cpp, **endcpp; 1004*51898Smckusick struct exportlist *ep; 1005*51898Smckusick struct grouplist *grp; 1006*51898Smckusick int *has_hostp; 1007*51898Smckusick int *exflagsp; 1008*51898Smckusick struct ucred *cr; 1009*51898Smckusick { 1010*51898Smckusick register char *cpoptarg, *cpoptend; 1011*51898Smckusick char *cp, *endcp, *cpopt, savedc, savedc2; 1012*51898Smckusick int allflag, usedarg; 1013*51898Smckusick 1014*51898Smckusick cpopt = *cpp; 1015*51898Smckusick cpopt++; 1016*51898Smckusick cp = *endcpp; 1017*51898Smckusick savedc = *cp; 1018*51898Smckusick *cp = '\0'; 1019*51898Smckusick while (cpopt && *cpopt) { 1020*51898Smckusick allflag = 1; 1021*51898Smckusick usedarg = -2; 1022*51898Smckusick if (cpoptend = index(cpopt, ',')) { 1023*51898Smckusick *cpoptend++ = '\0'; 1024*51898Smckusick if (cpoptarg = index(cpopt, '=')) 1025*51898Smckusick *cpoptarg++ = '\0'; 1026*51898Smckusick } else { 1027*51898Smckusick if (cpoptarg = index(cpopt, '=')) 1028*51898Smckusick *cpoptarg++ = '\0'; 1029*51898Smckusick else { 1030*51898Smckusick *cp = savedc; 1031*51898Smckusick nextfield(&cp, &endcp); 1032*51898Smckusick **endcpp = '\0'; 1033*51898Smckusick if (endcp > cp && *cp != '-') { 1034*51898Smckusick cpoptarg = cp; 1035*51898Smckusick savedc2 = *endcp; 1036*51898Smckusick *endcp = '\0'; 1037*51898Smckusick usedarg = 0; 103851667Smckusick } 103951667Smckusick } 104051667Smckusick } 1041*51898Smckusick if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1042*51898Smckusick *exflagsp |= MNT_EXRDONLY; 1043*51898Smckusick } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1044*51898Smckusick !(allflag = strcmp(cpopt, "mapall")) || 1045*51898Smckusick !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1046*51898Smckusick usedarg++; 1047*51898Smckusick parsecred(cpoptarg, cr); 1048*51898Smckusick if (allflag == 0) { 1049*51898Smckusick *exflagsp |= MNT_EXPORTANON; 1050*51898Smckusick opt_flags |= OP_MAPALL; 1051*51898Smckusick } else 1052*51898Smckusick opt_flags |= OP_MAPROOT; 1053*51898Smckusick } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 1054*51898Smckusick *exflagsp |= MNT_EXKERB; 1055*51898Smckusick opt_flags |= OP_KERB; 1056*51898Smckusick } else if (cpoptarg && !strcmp(cpopt, "mask")) { 1057*51898Smckusick if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1058*51898Smckusick syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 1059*51898Smckusick return (1); 1060*51898Smckusick } 1061*51898Smckusick usedarg++; 1062*51898Smckusick opt_flags |= OP_MASK; 1063*51898Smckusick } else if (cpoptarg && !strcmp(cpopt, "network")) { 1064*51898Smckusick if (grp->gr_type != GT_NULL) { 1065*51898Smckusick syslog(LOG_ERR, "Network/host conflict"); 1066*51898Smckusick return (1); 1067*51898Smckusick } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1068*51898Smckusick syslog(LOG_ERR, "Bad net: %s", cpoptarg); 1069*51898Smckusick return (1); 1070*51898Smckusick } 1071*51898Smckusick grp->gr_type = GT_NET; 1072*51898Smckusick *has_hostp = 1; 1073*51898Smckusick usedarg++; 1074*51898Smckusick opt_flags |= OP_NET; 1075*51898Smckusick } else if (!strcmp(cpopt, "alldirs")) { 1076*51898Smckusick opt_flags |= OP_ALLDIRS; 1077*51898Smckusick #ifdef ISO 1078*51898Smckusick } else if (cpoptarg && !strcmp(cpopt, "iso")) { 1079*51898Smckusick if (get_isoaddr(cpoptarg, grp)) { 1080*51898Smckusick syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 1081*51898Smckusick return (1); 1082*51898Smckusick } 1083*51898Smckusick *has_hostp = 1; 1084*51898Smckusick usedarg++; 1085*51898Smckusick opt_flags |= OP_ISO; 1086*51898Smckusick #endif /* ISO */ 1087*51898Smckusick } else { 1088*51898Smckusick syslog(LOG_ERR, "Bad opt %s", cpopt); 1089*51898Smckusick return (1); 109051667Smckusick } 1091*51898Smckusick if (usedarg >= 0) { 1092*51898Smckusick *endcp = savedc2; 1093*51898Smckusick **endcpp = savedc; 1094*51898Smckusick if (usedarg > 0) { 1095*51898Smckusick *cpp = cp; 1096*51898Smckusick *endcpp = endcp; 1097*51898Smckusick } 1098*51898Smckusick return (0); 1099*51898Smckusick } 1100*51898Smckusick cpopt = cpoptend; 110151667Smckusick } 1102*51898Smckusick **endcpp = savedc; 1103*51898Smckusick return (0); 1104*51898Smckusick } 1105*51898Smckusick 1106*51898Smckusick /* 1107*51898Smckusick * Translate a character string to the corresponding list of network 1108*51898Smckusick * addresses for a hostname. 1109*51898Smckusick */ 1110*51898Smckusick get_host(cp, grp) 1111*51898Smckusick char *cp; 1112*51898Smckusick register struct grouplist *grp; 1113*51898Smckusick { 1114*51898Smckusick register struct hostent *hp, *nhp; 1115*51898Smckusick register char **addrp, **naddrp; 1116*51898Smckusick struct hostent t_host; 1117*51898Smckusick int i; 1118*51898Smckusick u_long saddr; 1119*51898Smckusick char *aptr[2]; 1120*51898Smckusick 1121*51898Smckusick if (grp->gr_type != GT_NULL) 1122*51898Smckusick return (1); 1123*51898Smckusick if ((hp = gethostbyname(cp)) == NULL) { 1124*51898Smckusick if (isdigit(*cp)) { 1125*51898Smckusick saddr = inet_addr(cp); 1126*51898Smckusick if (saddr == -1) { 1127*51898Smckusick syslog(LOG_ERR, "Inet_addr failed"); 1128*51898Smckusick return (1); 1129*51898Smckusick } 1130*51898Smckusick if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 1131*51898Smckusick AF_INET)) == NULL) { 1132*51898Smckusick hp = &t_host; 1133*51898Smckusick hp->h_name = cp; 1134*51898Smckusick hp->h_addrtype = AF_INET; 1135*51898Smckusick hp->h_length = sizeof (u_long); 1136*51898Smckusick hp->h_addr_list = aptr; 1137*51898Smckusick aptr[0] = (char *)&saddr; 1138*51898Smckusick aptr[1] = (char *)0; 1139*51898Smckusick } 1140*51898Smckusick } else { 1141*51898Smckusick syslog(LOG_ERR, "Gethostbyname failed"); 1142*51898Smckusick return (1); 1143*51898Smckusick } 1144*51898Smckusick } 1145*51898Smckusick grp->gr_type = GT_HOST; 1146*51898Smckusick nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 1147*51898Smckusick malloc(sizeof(struct hostent)); 1148*51898Smckusick if (nhp == (struct hostent *)0) 1149*51898Smckusick out_of_mem(); 1150*51898Smckusick bcopy((caddr_t)hp, (caddr_t)nhp, 1151*51898Smckusick sizeof(struct hostent)); 1152*51898Smckusick i = strlen(hp->h_name)+1; 1153*51898Smckusick nhp->h_name = (char *)malloc(i); 1154*51898Smckusick if (nhp->h_name == (char *)0) 1155*51898Smckusick out_of_mem(); 1156*51898Smckusick bcopy(hp->h_name, nhp->h_name, i); 1157*51898Smckusick addrp = hp->h_addr_list; 1158*51898Smckusick i = 1; 1159*51898Smckusick while (*addrp++) 1160*51898Smckusick i++; 1161*51898Smckusick naddrp = nhp->h_addr_list = (char **) 1162*51898Smckusick malloc(i*sizeof(char *)); 1163*51898Smckusick if (naddrp == (char **)0) 1164*51898Smckusick out_of_mem(); 1165*51898Smckusick addrp = hp->h_addr_list; 1166*51898Smckusick while (*addrp) { 1167*51898Smckusick *naddrp = (char *) 1168*51898Smckusick malloc(hp->h_length); 1169*51898Smckusick if (*naddrp == (char *)0) 1170*51898Smckusick out_of_mem(); 1171*51898Smckusick bcopy(*addrp, *naddrp, 1172*51898Smckusick hp->h_length); 1173*51898Smckusick addrp++; 1174*51898Smckusick naddrp++; 1175*51898Smckusick } 1176*51898Smckusick *naddrp = (char *)0; 1177*51898Smckusick return (0); 1178*51898Smckusick } 1179*51898Smckusick 1180*51898Smckusick /* 1181*51898Smckusick * Free up an exports list component 1182*51898Smckusick */ 1183*51898Smckusick void 1184*51898Smckusick free_exp(ep) 1185*51898Smckusick register struct exportlist *ep; 1186*51898Smckusick { 1187*51898Smckusick 1188*51898Smckusick if (ep->ex_defdir) { 1189*51898Smckusick free_host(ep->ex_defdir->dp_hosts); 1190*51898Smckusick free((caddr_t)ep->ex_defdir); 1191*51898Smckusick } 1192*51898Smckusick if (ep->ex_fsdir) 1193*51898Smckusick free(ep->ex_fsdir); 1194*51898Smckusick free_dir(ep->ex_dirl); 1195*51898Smckusick free((caddr_t)ep); 1196*51898Smckusick } 1197*51898Smckusick 1198*51898Smckusick /* 1199*51898Smckusick * Free hosts. 1200*51898Smckusick */ 1201*51898Smckusick void 1202*51898Smckusick free_host(hp) 1203*51898Smckusick register struct hostlist *hp; 1204*51898Smckusick { 1205*51898Smckusick register struct hostlist *hp2; 1206*51898Smckusick 1207*51898Smckusick while (hp) { 1208*51898Smckusick hp2 = hp; 1209*51898Smckusick hp = hp->ht_next; 1210*51898Smckusick free((caddr_t)hp2); 1211*51898Smckusick } 1212*51898Smckusick } 1213*51898Smckusick 1214*51898Smckusick struct hostlist * 1215*51898Smckusick get_ht() 1216*51898Smckusick { 1217*51898Smckusick register struct hostlist *hp; 1218*51898Smckusick 1219*51898Smckusick hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 1220*51898Smckusick if (hp == (struct hostlist *)0) 1221*51898Smckusick out_of_mem(); 1222*51898Smckusick hp->ht_next = (struct hostlist *)0; 1223*51898Smckusick return (hp); 1224*51898Smckusick } 1225*51898Smckusick 1226*51898Smckusick #ifdef ISO 1227*51898Smckusick /* 1228*51898Smckusick * Translate an iso address. 1229*51898Smckusick */ 1230*51898Smckusick get_isoaddr(cp, grp) 1231*51898Smckusick char *cp; 1232*51898Smckusick struct grouplist *grp; 1233*51898Smckusick { 1234*51898Smckusick struct iso_addr *isop; 1235*51898Smckusick struct sockaddr_iso *isoaddr; 1236*51898Smckusick 1237*51898Smckusick if (grp->gr_type != GT_NULL) 1238*51898Smckusick return (1); 1239*51898Smckusick if ((isop = iso_addr(cp)) == NULL) { 1240*51898Smckusick syslog(LOG_ERR, 1241*51898Smckusick "iso_addr failed, ignored"); 1242*51898Smckusick return (1); 1243*51898Smckusick } 1244*51898Smckusick isoaddr = (struct sockaddr_iso *) 1245*51898Smckusick malloc(sizeof (struct sockaddr_iso)); 1246*51898Smckusick if (isoaddr == (struct sockaddr_iso *)0) 1247*51898Smckusick out_of_mem(); 1248*51898Smckusick bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 1249*51898Smckusick bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 1250*51898Smckusick sizeof (struct iso_addr)); 1251*51898Smckusick isoaddr->siso_len = sizeof (struct sockaddr_iso); 1252*51898Smckusick isoaddr->siso_family = AF_ISO; 1253*51898Smckusick grp->gr_type = GT_ISO; 1254*51898Smckusick grp->gr_ptr.gt_isoaddr = isoaddr; 1255*51898Smckusick return (0); 1256*51898Smckusick } 1257*51898Smckusick #endif /* ISO */ 1258*51898Smckusick 1259*51898Smckusick /* 1260*51898Smckusick * Out of memory, fatal 1261*51898Smckusick */ 1262*51898Smckusick void 1263*51898Smckusick out_of_mem() 1264*51898Smckusick { 1265*51898Smckusick 1266*51898Smckusick syslog(LOG_ERR, "Out of memory"); 126751667Smckusick exit(2); 126851667Smckusick } 126951667Smckusick 1270*51898Smckusick /* 1271*51898Smckusick * Do the mount syscall with the update flag to push the export info into 1272*51898Smckusick * the kernel. 1273*51898Smckusick */ 1274*51898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 127551667Smckusick struct exportlist *ep; 127651667Smckusick struct grouplist *grp; 1277*51898Smckusick int exflags; 127851667Smckusick struct ucred *anoncrp; 1279*51898Smckusick char *dirp; 1280*51898Smckusick int dirplen; 1281*51898Smckusick struct statfs *fsb; 128251667Smckusick { 1283*51898Smckusick register char *cp = (char *)0; 128451667Smckusick register u_long **addrp; 1285*51898Smckusick int done; 1286*51898Smckusick char savedc; 1287*51898Smckusick struct sockaddr_in sin, imask; 128851667Smckusick struct ufs_args args, targs; 1289*51898Smckusick u_long net; 129051667Smckusick 129151667Smckusick args.fspec = 0; 129251667Smckusick args.exflags = exflags; 129351667Smckusick args.anon = *anoncrp; 129451667Smckusick sin.sin_family = AF_INET; 129551667Smckusick sin.sin_port = 0; 129651667Smckusick sin.sin_len = sizeof(sin); 1297*51898Smckusick imask.sin_family = AF_INET; 1298*51898Smckusick imask.sin_port = 0; 1299*51898Smckusick imask.sin_len = sizeof(sin); 1300*51898Smckusick if (grp->gr_type == GT_HOST) 130151667Smckusick addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 1302*51898Smckusick else 1303*51898Smckusick addrp = (u_long **)0; 130451667Smckusick done = FALSE; 1305*51898Smckusick while (!done) { 1306*51898Smckusick switch (grp->gr_type) { 1307*51898Smckusick case GT_HOST: 1308*51898Smckusick if (addrp) 130951712Smckusick sin.sin_addr.s_addr = **addrp; 131051712Smckusick else 131151667Smckusick sin.sin_addr.s_addr = INADDR_ANY; 131251667Smckusick args.saddr = (struct sockaddr *)&sin; 131351667Smckusick args.slen = sizeof(sin); 1314*51898Smckusick args.msklen = 0; 1315*51898Smckusick break; 1316*51898Smckusick case GT_NET: 1317*51898Smckusick if (grp->gr_ptr.gt_net.nt_mask) 1318*51898Smckusick imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 1319*51898Smckusick else { 1320*51898Smckusick net = ntohl(grp->gr_ptr.gt_net.nt_net); 1321*51898Smckusick if (IN_CLASSA(net)) 1322*51898Smckusick imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 1323*51898Smckusick else if (IN_CLASSB(net)) 1324*51898Smckusick imask.sin_addr.s_addr = 1325*51898Smckusick inet_addr("255.255.0.0"); 1326*51898Smckusick else 1327*51898Smckusick imask.sin_addr.s_addr = 1328*51898Smckusick inet_addr("255.255.255.0"); 1329*51898Smckusick grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 1330*51898Smckusick } 1331*51898Smckusick sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 1332*51898Smckusick args.saddr = (struct sockaddr *)&sin; 1333*51898Smckusick args.slen = sizeof (sin); 1334*51898Smckusick args.smask = (struct sockaddr *)&imask; 1335*51898Smckusick args.msklen = sizeof (imask); 1336*51898Smckusick break; 133751667Smckusick #ifdef ISO 1338*51898Smckusick case GT_ISO: 133951667Smckusick args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 134051667Smckusick args.slen = sizeof (struct sockaddr_iso); 1341*51898Smckusick args.msklen = 0; 1342*51898Smckusick break; 134351667Smckusick #endif /* ISO */ 1344*51898Smckusick default: 134551667Smckusick syslog(LOG_ERR, "Bad grouptype"); 1346*51898Smckusick if (cp) 1347*51898Smckusick *cp = savedc; 1348*51898Smckusick return (1); 1349*51898Smckusick }; 1350*51898Smckusick if ((ep->ex_flag & EX_DONEDEL) == 0) { 1351*51898Smckusick /* 1352*51898Smckusick * first time for fs, so must send a MNT_DELEXPORT 135351667Smckusick * to clear the old export list held in the kernel 135451667Smckusick * for this fs. 135551667Smckusick */ 135651667Smckusick targs.fspec = 0; 135751667Smckusick targs.exflags = MNT_DELEXPORT; 1358*51898Smckusick while (mount(MOUNT_UFS, dirp, 1359*51898Smckusick fsb->f_flags | MNT_UPDATE, &targs) < 0) { 1360*51898Smckusick if (debug) 136151667Smckusick fprintf(stderr, 136251667Smckusick "tried [%s][%d]\n", 1363*51898Smckusick dirp,errno); 1364*51898Smckusick if (cp) 1365*51898Smckusick *cp-- = savedc; 1366*51898Smckusick else 1367*51898Smckusick cp = dirp + dirplen - 1; 1368*51898Smckusick if (opt_flags & OP_ALLDIRS) { 1369*51898Smckusick syslog(LOG_ERR, "Not root dir"); 1370*51898Smckusick return (1); 137151667Smckusick } 137244015Smckusick /* back up over the last component */ 1373*51898Smckusick while (*cp == '/' && cp > dirp) 137444015Smckusick cp--; 1375*51898Smckusick while (*(cp - 1) != '/' && cp > dirp) 137644015Smckusick cp--; 1377*51898Smckusick if (cp == dirp) { 1378*51898Smckusick if (debug) 137951667Smckusick fprintf(stderr,"mnt unsucc\n"); 138051667Smckusick syslog(LOG_ERR, 1381*51898Smckusick "Can't export %s", dirp); 1382*51898Smckusick return (1); 138344015Smckusick } 138444015Smckusick savedc = *cp; 138544015Smckusick *cp = '\0'; 138644015Smckusick } 1387*51898Smckusick ep->ex_flag |= EX_DONEDEL; 138838460Smckusick } 1389*51898Smckusick while (mount(MOUNT_UFS, dirp, 1390*51898Smckusick fsb->f_flags | MNT_UPDATE, &args) < 0) { 1391*51898Smckusick if (cp) 1392*51898Smckusick *cp-- = savedc; 1393*51898Smckusick else 1394*51898Smckusick cp = dirp + dirplen - 1; 139551667Smckusick if (errno == EPERM) { 139651667Smckusick syslog(LOG_ERR, 1397*51898Smckusick "Can't change attributes for %s.\n", dirp); 1398*51898Smckusick return (1); 139951667Smckusick } 1400*51898Smckusick if (opt_flags & OP_ALLDIRS) { 1401*51898Smckusick syslog(LOG_ERR, "Not root dir"); 1402*51898Smckusick return (1); 1403*51898Smckusick } 140451667Smckusick /* back up over the last component */ 1405*51898Smckusick while (*cp == '/' && cp > dirp) 140651667Smckusick cp--; 1407*51898Smckusick while (*(cp - 1) != '/' && cp > dirp) 140851667Smckusick cp--; 1409*51898Smckusick if (cp == dirp) { 1410*51898Smckusick if (debug) 141151667Smckusick fprintf(stderr,"mnt unsucc\n"); 1412*51898Smckusick syslog(LOG_ERR, "Can't export %s", dirp); 1413*51898Smckusick return (1); 141451667Smckusick } 141551667Smckusick savedc = *cp; 141651667Smckusick *cp = '\0'; 141751667Smckusick } 1418*51898Smckusick if (addrp) { 141951667Smckusick ++addrp; 1420*51898Smckusick if (*addrp == (u_long *)0) 142151667Smckusick done = TRUE; 1422*51898Smckusick } else 1423*51898Smckusick done = TRUE; 1424*51898Smckusick } 1425*51898Smckusick if (cp) 1426*51898Smckusick *cp = savedc; 1427*51898Smckusick return (0); 1428*51898Smckusick } 1429*51898Smckusick 1430*51898Smckusick /* 1431*51898Smckusick * Translate a net address. 1432*51898Smckusick */ 1433*51898Smckusick get_net(cp, net, maskflg) 1434*51898Smckusick char *cp; 1435*51898Smckusick struct netmsk *net; 1436*51898Smckusick int maskflg; 1437*51898Smckusick { 1438*51898Smckusick register struct netent *np; 1439*51898Smckusick register long netaddr; 1440*51898Smckusick struct in_addr inetaddr, inetaddr2; 1441*51898Smckusick char *name; 1442*51898Smckusick 1443*51898Smckusick if (np = getnetbyname(cp)) 1444*51898Smckusick inetaddr = inet_makeaddr(np->n_net, 0); 1445*51898Smckusick else if (isdigit(*cp)) { 1446*51898Smckusick if ((netaddr = inet_network(cp)) == -1) 1447*51898Smckusick return (1); 1448*51898Smckusick inetaddr = inet_makeaddr(netaddr, 0); 1449*51898Smckusick /* 1450*51898Smckusick * Due to arbritrary subnet masks, you don't know how many 1451*51898Smckusick * bits to shift the address to make it into a network, 1452*51898Smckusick * however you do know how to make a network address into 1453*51898Smckusick * a host with host == 0 and then compare them. 1454*51898Smckusick * (What a pest) 1455*51898Smckusick */ 1456*51898Smckusick if (!maskflg) { 1457*51898Smckusick setnetent(0); 1458*51898Smckusick while (np = getnetent()) { 1459*51898Smckusick inetaddr2 = inet_makeaddr(np->n_net, 0); 1460*51898Smckusick if (inetaddr2.s_addr == inetaddr.s_addr) 1461*51898Smckusick break; 1462*51898Smckusick } 1463*51898Smckusick endnetent(); 146451667Smckusick } 1465*51898Smckusick } else 1466*51898Smckusick return (1); 1467*51898Smckusick if (maskflg) 1468*51898Smckusick net->nt_mask = inetaddr.s_addr; 1469*51898Smckusick else { 1470*51898Smckusick if (np) 1471*51898Smckusick name = np->n_name; 1472*51898Smckusick else 1473*51898Smckusick name = inet_ntoa(inetaddr); 1474*51898Smckusick net->nt_name = (char *)malloc(strlen(name) + 1); 1475*51898Smckusick if (net->nt_name == (char *)0) 1476*51898Smckusick out_of_mem(); 1477*51898Smckusick strcpy(net->nt_name, name); 1478*51898Smckusick net->nt_net = inetaddr.s_addr; 147938460Smckusick } 1480*51898Smckusick return (0); 148138460Smckusick } 148238460Smckusick 148338460Smckusick /* 148438460Smckusick * Parse out the next white space separated field 148538460Smckusick */ 148651667Smckusick void 148738460Smckusick nextfield(cp, endcp) 148838460Smckusick char **cp; 148938460Smckusick char **endcp; 149038460Smckusick { 149138460Smckusick register char *p; 149238460Smckusick 149338460Smckusick p = *cp; 149438460Smckusick while (*p == ' ' || *p == '\t') 149538460Smckusick p++; 1496*51898Smckusick if (*p == '\n' || *p == '\0') 149738460Smckusick *cp = *endcp = p; 1498*51898Smckusick else { 1499*51898Smckusick *cp = p++; 1500*51898Smckusick while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 1501*51898Smckusick p++; 1502*51898Smckusick *endcp = p; 150338460Smckusick } 150438460Smckusick } 150539681Smckusick 150639681Smckusick /* 1507*51898Smckusick * Get an exports file line. Skip over blank lines and handle line 1508*51898Smckusick * continuations. 150939681Smckusick */ 1510*51898Smckusick get_line() 151139681Smckusick { 1512*51898Smckusick register char *p, *cp; 1513*51898Smckusick register int len; 1514*51898Smckusick int totlen, cont_line; 151539681Smckusick 1516*51898Smckusick /* 1517*51898Smckusick * Loop around ignoring blank lines and getting all continuation lines. 1518*51898Smckusick */ 1519*51898Smckusick p = line; 1520*51898Smckusick totlen = 0; 1521*51898Smckusick do { 1522*51898Smckusick if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 1523*51898Smckusick return (0); 1524*51898Smckusick len = strlen(p); 1525*51898Smckusick cp = p + len - 1; 1526*51898Smckusick cont_line = 0; 1527*51898Smckusick while (cp >= p && 1528*51898Smckusick (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 1529*51898Smckusick if (*cp == '\\') 1530*51898Smckusick cont_line = 1; 1531*51898Smckusick cp--; 1532*51898Smckusick len--; 1533*51898Smckusick } 1534*51898Smckusick *++cp = '\0'; 1535*51898Smckusick if (len > 0) { 1536*51898Smckusick totlen += len; 1537*51898Smckusick if (totlen >= LINESIZ) { 1538*51898Smckusick syslog(LOG_ERR, "Exports line too long"); 1539*51898Smckusick exit(2); 1540*51898Smckusick } 1541*51898Smckusick p = cp; 1542*51898Smckusick } 1543*51898Smckusick } while (totlen == 0 || cont_line); 1544*51898Smckusick return (1); 154544015Smckusick } 154644015Smckusick 154751667Smckusick /* 154851667Smckusick * Parse a description of a credential. 154951667Smckusick */ 155051667Smckusick parsecred(namelist, cr) 155151667Smckusick char *namelist; 155251667Smckusick register struct ucred *cr; 155351667Smckusick { 155451667Smckusick register char *name; 155551667Smckusick register int cnt; 155651667Smckusick char *names; 155751667Smckusick struct passwd *pw; 155851667Smckusick struct group *gr; 155951667Smckusick int ngroups, groups[NGROUPS + 1]; 156051667Smckusick 156151667Smckusick /* 156251667Smckusick * Set up the unpriviledged user. 156351667Smckusick */ 156451667Smckusick cr->cr_ref = 1; 156551667Smckusick cr->cr_uid = -2; 156651667Smckusick cr->cr_groups[0] = -2; 156751667Smckusick cr->cr_ngroups = 1; 156851667Smckusick /* 156951667Smckusick * Get the user's password table entry. 157051667Smckusick */ 157151667Smckusick names = strsep(&namelist, " \t\n"); 157251667Smckusick name = strsep(&names, ":"); 157351667Smckusick if (isdigit(*name) || *name == '-') 157451667Smckusick pw = getpwuid(atoi(name)); 157551667Smckusick else 157651667Smckusick pw = getpwnam(name); 157751667Smckusick /* 157851667Smckusick * Credentials specified as those of a user. 157951667Smckusick */ 158051667Smckusick if (names == NULL) { 158151667Smckusick if (pw == NULL) { 158251667Smckusick syslog(LOG_ERR, "Unknown user: %s\n", name); 158351667Smckusick return; 158451667Smckusick } 158551667Smckusick cr->cr_uid = pw->pw_uid; 158651667Smckusick ngroups = NGROUPS + 1; 158751667Smckusick if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 158851667Smckusick syslog(LOG_ERR, "Too many groups\n"); 158951667Smckusick /* 159051667Smckusick * Convert from int's to gid_t's and compress out duplicate 159151667Smckusick */ 159251667Smckusick cr->cr_ngroups = ngroups - 1; 159351667Smckusick cr->cr_groups[0] = groups[0]; 159451667Smckusick for (cnt = 2; cnt < ngroups; cnt++) 159551667Smckusick cr->cr_groups[cnt - 1] = groups[cnt]; 159651667Smckusick return; 159751667Smckusick } 159851667Smckusick /* 159951667Smckusick * Explicit credential specified as a colon separated list: 160051667Smckusick * uid:gid:gid:... 160151667Smckusick */ 160251667Smckusick if (pw != NULL) 160351667Smckusick cr->cr_uid = pw->pw_uid; 160451667Smckusick else if (isdigit(*name) || *name == '-') 160551667Smckusick cr->cr_uid = atoi(name); 160651667Smckusick else { 160751667Smckusick syslog(LOG_ERR, "Unknown user: %s\n", name); 160851667Smckusick return; 160951667Smckusick } 161051667Smckusick cr->cr_ngroups = 0; 161151667Smckusick while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 161251667Smckusick name = strsep(&names, ":"); 161351667Smckusick if (isdigit(*name) || *name == '-') { 161451667Smckusick cr->cr_groups[cr->cr_ngroups++] = atoi(name); 161551667Smckusick } else { 161651667Smckusick if ((gr = getgrnam(name)) == NULL) { 161751667Smckusick syslog(LOG_ERR, "Unknown group: %s\n", name); 161851667Smckusick continue; 161951667Smckusick } 162051667Smckusick cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 162151667Smckusick } 162251667Smckusick } 162351667Smckusick if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 162451667Smckusick syslog(LOG_ERR, "Too many groups\n"); 162551667Smckusick } 162651667Smckusick 162744015Smckusick #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 162844015Smckusick /* 162944015Smckusick * Routines that maintain the remote mounttab 163044015Smckusick */ 163151667Smckusick void 163251667Smckusick get_mountlist() 163344015Smckusick { 163444015Smckusick register struct mountlist *mlp, **mlpp; 163544015Smckusick register char *eos, *dirp; 163644015Smckusick int len; 163744015Smckusick char str[STRSIZ]; 163844015Smckusick FILE *mlfile; 163944015Smckusick 164051712Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 164151667Smckusick syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 164244015Smckusick return; 164344015Smckusick } 164444015Smckusick mlpp = &mlhead; 164544015Smckusick while (fgets(str, STRSIZ, mlfile) != NULL) { 164644015Smckusick if ((dirp = index(str, '\t')) == NULL && 164744015Smckusick (dirp = index(str, ' ')) == NULL) 164844015Smckusick continue; 164944015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 165044015Smckusick len = dirp-str; 165144015Smckusick if (len > RPCMNT_NAMELEN) 165244015Smckusick len = RPCMNT_NAMELEN; 165344015Smckusick bcopy(str, mlp->ml_host, len); 165444015Smckusick mlp->ml_host[len] = '\0'; 165544015Smckusick while (*dirp == '\t' || *dirp == ' ') 165644015Smckusick dirp++; 165744015Smckusick if ((eos = index(dirp, '\t')) == NULL && 165844015Smckusick (eos = index(dirp, ' ')) == NULL && 165944015Smckusick (eos = index(dirp, '\n')) == NULL) 166044015Smckusick len = strlen(dirp); 166144015Smckusick else 166244015Smckusick len = eos-dirp; 166344015Smckusick if (len > RPCMNT_PATHLEN) 166444015Smckusick len = RPCMNT_PATHLEN; 166544015Smckusick bcopy(dirp, mlp->ml_dirp, len); 166644015Smckusick mlp->ml_dirp[len] = '\0'; 166744015Smckusick mlp->ml_next = (struct mountlist *)0; 166844015Smckusick *mlpp = mlp; 166944015Smckusick mlpp = &mlp->ml_next; 167044015Smckusick } 167144015Smckusick fclose(mlfile); 167244015Smckusick } 167344015Smckusick 167451667Smckusick void 167551667Smckusick del_mlist(hostp, dirp) 167644015Smckusick register char *hostp, *dirp; 167744015Smckusick { 167844015Smckusick register struct mountlist *mlp, **mlpp; 167951712Smckusick struct mountlist *mlp2; 168044015Smckusick FILE *mlfile; 168144015Smckusick int fnd = 0; 168244015Smckusick 168344015Smckusick mlpp = &mlhead; 168444015Smckusick mlp = mlhead; 168544015Smckusick while (mlp) { 168644015Smckusick if (!strcmp(mlp->ml_host, hostp) && 168744015Smckusick (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 168844015Smckusick fnd = 1; 168951712Smckusick mlp2 = mlp; 169051712Smckusick *mlpp = mlp = mlp->ml_next; 169151712Smckusick free((caddr_t)mlp2); 169251712Smckusick } else { 169351712Smckusick mlpp = &mlp->ml_next; 169451712Smckusick mlp = mlp->ml_next; 169539681Smckusick } 169639681Smckusick } 169744015Smckusick if (fnd) { 169844015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 1699*51898Smckusick syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 170044015Smckusick return; 170144015Smckusick } 170244015Smckusick mlp = mlhead; 170344015Smckusick while (mlp) { 170444015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 170544015Smckusick mlp = mlp->ml_next; 170644015Smckusick } 170744015Smckusick fclose(mlfile); 170844015Smckusick } 170939681Smckusick } 171044015Smckusick 171151667Smckusick void 171251667Smckusick add_mlist(hostp, dirp) 171344015Smckusick register char *hostp, *dirp; 171444015Smckusick { 171544015Smckusick register struct mountlist *mlp, **mlpp; 171644015Smckusick FILE *mlfile; 171744015Smckusick 171844015Smckusick mlpp = &mlhead; 171944015Smckusick mlp = mlhead; 172044015Smckusick while (mlp) { 172144015Smckusick if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 172244015Smckusick return; 172344015Smckusick mlpp = &mlp->ml_next; 172444015Smckusick mlp = mlp->ml_next; 172544015Smckusick } 172644015Smckusick mlp = (struct mountlist *)malloc(sizeof (*mlp)); 172744015Smckusick strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 172844015Smckusick mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 172944015Smckusick strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 173044015Smckusick mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 173144015Smckusick mlp->ml_next = (struct mountlist *)0; 173244015Smckusick *mlpp = mlp; 173344015Smckusick if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 1734*51898Smckusick syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 173544015Smckusick return; 173644015Smckusick } 173744015Smckusick fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 173844015Smckusick fclose(mlfile); 173944015Smckusick } 174044015Smckusick 174144015Smckusick /* 174244015Smckusick * This function is called via. SIGTERM when the system is going down. 174344015Smckusick * It sends a broadcast RPCMNT_UMNTALL. 174444015Smckusick */ 174546709Sbostic void 174644015Smckusick send_umntall() 174744015Smckusick { 174844015Smckusick (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 174944015Smckusick xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 175051667Smckusick exit(0); 175144015Smckusick } 175244015Smckusick 175344015Smckusick umntall_each(resultsp, raddr) 175444015Smckusick caddr_t resultsp; 175544015Smckusick struct sockaddr_in *raddr; 175644015Smckusick { 175744015Smckusick return (1); 175844015Smckusick } 175944015Smckusick 176044015Smckusick /* 176151667Smckusick * Free up a group list. 176251667Smckusick */ 176351667Smckusick void 176451667Smckusick free_grp(grp) 176551667Smckusick register struct grouplist *grp; 176651667Smckusick { 176751667Smckusick register char **addrp; 176851667Smckusick 1769*51898Smckusick if (grp->gr_type == GT_HOST) { 177051712Smckusick if (grp->gr_ptr.gt_hostent->h_name) { 177151712Smckusick addrp = grp->gr_ptr.gt_hostent->h_addr_list; 177251712Smckusick while (addrp && *addrp) 177351712Smckusick free(*addrp++); 177451712Smckusick free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 177551712Smckusick free(grp->gr_ptr.gt_hostent->h_name); 177651712Smckusick } 177751667Smckusick free((caddr_t)grp->gr_ptr.gt_hostent); 1778*51898Smckusick } else if (grp->gr_type == GT_NET) { 1779*51898Smckusick if (grp->gr_ptr.gt_net.nt_name) 1780*51898Smckusick free(grp->gr_ptr.gt_net.nt_name); 178151667Smckusick } 178251667Smckusick #ifdef ISO 1783*51898Smckusick else if (grp->gr_type == GT_ISO) 178451667Smckusick free((caddr_t)grp->gr_ptr.gt_isoaddr); 178551667Smckusick #endif 178651667Smckusick free((caddr_t)grp); 178751667Smckusick } 178851667Smckusick 178951667Smckusick /* 179051667Smckusick * char *realpath(const char *path, char resolved_path[MAXPATHLEN]) 179151667Smckusick * 179251667Smckusick * find the real name of path, by removing all ".", ".." 179351667Smckusick * and symlink components. 179451667Smckusick * 179551667Smckusick * Jan-Simon Pendry, September 1991. 179651667Smckusick */ 179751667Smckusick char * 179851667Smckusick realpath(path, resolved) 179951667Smckusick char *path; 180051667Smckusick char resolved[MAXPATHLEN]; 180151667Smckusick { 180251667Smckusick int d = open(".", O_RDONLY); 180351667Smckusick int rootd = 0; 180451667Smckusick char *p, *q; 180551667Smckusick struct stat stb; 180651667Smckusick char wbuf[MAXPATHLEN]; 180751667Smckusick 180851667Smckusick strcpy(resolved, path); 180951667Smckusick 181051667Smckusick if (d < 0) 181151667Smckusick return 0; 181251667Smckusick 181351667Smckusick loop:; 181451667Smckusick q = strrchr(resolved, '/'); 181551667Smckusick if (q) { 181651667Smckusick p = q + 1; 181751667Smckusick if (q == resolved) 181851667Smckusick q = "/"; 181951667Smckusick else { 182051667Smckusick do 182151667Smckusick --q; 182251667Smckusick while (q > resolved && *q == '/'); 182351667Smckusick q[1] = '\0'; 182451667Smckusick q = resolved; 182551667Smckusick } 182651667Smckusick if (chdir(q) < 0) 182751667Smckusick goto out; 182851667Smckusick } else 182951667Smckusick p = resolved; 183051667Smckusick 183151667Smckusick if (lstat(p, &stb) == 0) { 183251667Smckusick if (S_ISLNK(stb.st_mode)) { 183351667Smckusick int n = readlink(p, resolved, MAXPATHLEN); 183451667Smckusick if (n < 0) 183551667Smckusick goto out; 183651667Smckusick resolved[n] = '\0'; 183751667Smckusick goto loop; 183851667Smckusick } 183951667Smckusick if (S_ISDIR(stb.st_mode)) { 184051667Smckusick if (chdir(p) < 0) 184151667Smckusick goto out; 184251667Smckusick p = ""; 184351667Smckusick } 184451667Smckusick } 184551667Smckusick 184651667Smckusick strcpy(wbuf, p); 184751667Smckusick if (getcwd(resolved, MAXPATHLEN) == 0) 184851667Smckusick goto out; 184951667Smckusick if (resolved[0] == '/' && resolved[1] == '\0') 185051667Smckusick rootd = 1; 185151667Smckusick 185251667Smckusick if (*wbuf) { 185351667Smckusick if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) { 185451667Smckusick errno = ENAMETOOLONG; 185551667Smckusick goto out; 185651667Smckusick } 185751667Smckusick if (rootd == 0) 185851667Smckusick strcat(resolved, "/"); 185951667Smckusick strcat(resolved, wbuf); 186051667Smckusick } 186151667Smckusick 186251667Smckusick if (fchdir(d) < 0) 186351667Smckusick goto out; 186451667Smckusick (void) close(d); 186551667Smckusick 186651667Smckusick return resolved; 186751667Smckusick 186851667Smckusick out:; 186951667Smckusick (void) close(d); 187051667Smckusick return 0; 187151667Smckusick } 187251711Smckusick 187351711Smckusick #ifdef DEBUG 187451711Smckusick void 187551711Smckusick SYSLOG(int pri, const char *fmt, ...) 187651711Smckusick { 187751711Smckusick va_list ap; 187851711Smckusick 187951711Smckusick va_start(ap, fmt); 188051711Smckusick vfprintf(stderr, fmt, ap); 188151711Smckusick va_end(ap); 188251711Smckusick } 188351711Smckusick #endif /* DEBUG */ 1884*51898Smckusick 1885*51898Smckusick /* 1886*51898Smckusick * Check options for consistency. 1887*51898Smckusick */ 1888*51898Smckusick check_options(dp) 1889*51898Smckusick struct dirlist *dp; 1890*51898Smckusick { 1891*51898Smckusick 1892*51898Smckusick if (dp == (struct dirlist *)0) 1893*51898Smckusick return (1); 1894*51898Smckusick if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 1895*51898Smckusick (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 1896*51898Smckusick (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 1897*51898Smckusick syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 1898*51898Smckusick return (1); 1899*51898Smckusick } 1900*51898Smckusick if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 1901*51898Smckusick syslog(LOG_ERR, "-mask requires -net"); 1902*51898Smckusick return (1); 1903*51898Smckusick } 1904*51898Smckusick if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 1905*51898Smckusick syslog(LOG_ERR, "-net and -iso mutually exclusive"); 1906*51898Smckusick return (1); 1907*51898Smckusick } 1908*51898Smckusick if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 1909*51898Smckusick syslog(LOG_ERR, "-alldir has multiple directories"); 1910*51898Smckusick return (1); 1911*51898Smckusick } 1912*51898Smckusick return (0); 1913*51898Smckusick } 1914