📄 mountd.c
字号:
/* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Herb Hasler and Rick Macklem at The University of Guelph. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n";#endif not lint#ifndef lintstatic char sccsid[] = "@(#)mountd.c 8.8 (Berkeley) 2/20/94";#endif not lint#include <sys/param.h>#include <sys/file.h>#include <sys/ioctl.h>#include <sys/mount.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/syslog.h>#include <sys/ucred.h>#include <rpc/rpc.h>#include <rpc/pmap_clnt.h>#include <rpc/pmap_prot.h>#ifdef ISO#include <netiso/iso.h>#endif#include <nfs/rpcv2.h>#include <nfs/nfsv2.h>#include <arpa/inet.h>#include <ctype.h>#include <errno.h>#include <grp.h>#include <netdb.h>#include <pwd.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "pathnames.h"#ifdef DEBUG#include <stdarg.h>#endif/* * Structures for keeping the mount list and export list */struct mountlist { struct mountlist *ml_next; char ml_host[RPCMNT_NAMELEN+1]; char ml_dirp[RPCMNT_PATHLEN+1];};struct dirlist { struct dirlist *dp_left; struct dirlist *dp_right; int dp_flag; struct hostlist *dp_hosts; /* List of hosts this dir exported to */ char dp_dirp[1]; /* Actually malloc'd to size of dir */};/* dp_flag bits */#define DP_DEFSET 0x1struct exportlist { struct exportlist *ex_next; struct dirlist *ex_dirl; struct dirlist *ex_defdir; int ex_flag; fsid_t ex_fs; char *ex_fsdir;};/* ex_flag bits */#define EX_LINKED 0x1struct netmsk { u_long nt_net; u_long nt_mask; char *nt_name;};union grouptypes { struct hostent *gt_hostent; struct netmsk gt_net;#ifdef ISO struct sockaddr_iso *gt_isoaddr;#endif};struct grouplist { int gr_type; union grouptypes gr_ptr; struct grouplist *gr_next;};/* Group types */#define GT_NULL 0x0#define GT_HOST 0x1#define GT_NET 0x2#define GT_ISO 0x4struct hostlist { struct grouplist *ht_grp; struct hostlist *ht_next;};/* Global defs */char *add_expdir __P((struct dirlist **, char *, int));void add_dlist __P((struct dirlist **, struct dirlist *, struct grouplist *));void add_mlist __P((char *, char *));int check_dirpath __P((char *));int check_options __P((struct dirlist *));int chk_host __P((struct dirlist *, u_long, int *));void del_mlist __P((char *, char *));struct dirlist *dirp_search __P((struct dirlist *, char *));int do_mount __P((struct exportlist *, struct grouplist *, int, struct ucred *, char *, int, struct statfs *));int do_opt __P((char **, char **, struct exportlist *, struct grouplist *, int *, int *, struct ucred *));struct exportlist *ex_search __P((fsid_t *));struct exportlist *get_exp __P((void));void free_dir __P((struct dirlist *));void free_exp __P((struct exportlist *));void free_grp __P((struct grouplist *));void free_host __P((struct hostlist *));void get_exportlist __P((void));int get_host __P((char *, struct grouplist *));struct hostlist *get_ht __P((void));int get_line __P((void));void get_mountlist __P((void));int get_net __P((char *, struct netmsk *, int));void getexp_err __P((struct exportlist *, struct grouplist *));struct grouplist *get_grp __P((void));void hang_dirp __P((struct dirlist *, struct grouplist *, struct exportlist *, int));void mntsrv __P((struct svc_req *, SVCXPRT *));void nextfield __P((char **, char **));void out_of_mem __P((void));void parsecred __P((char *, struct ucred *));int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));int scan_tree __P((struct dirlist *, u_long));void send_umntall __P((void));int umntall_each __P((caddr_t, struct sockaddr_in *));int xdr_dir __P((XDR *, char *));int xdr_explist __P((XDR *, caddr_t));int xdr_fhs __P((XDR *, nfsv2fh_t *));int xdr_mlist __P((XDR *, caddr_t));/* C library */int getnetgrent();void endnetgrent();void setnetgrent();#ifdef ISOstruct iso_addr *iso_addr();#endifstruct exportlist *exphead;struct mountlist *mlhead;struct grouplist *grphead;char exname[MAXPATHLEN];struct ucred def_anon = { 1, (uid_t) -2, 1, { (gid_t) -2 }};int root_only = 1;int opt_flags;/* Bits for above */#define OP_MAPROOT 0x01#define OP_MAPALL 0x02#define OP_KERB 0x04#define OP_MASK 0x08#define OP_NET 0x10#define OP_ISO 0x20#define OP_ALLDIRS 0x40#ifdef DEBUGint debug = 1;void SYSLOG __P((int, const char *, ...));#define syslog SYSLOG#elseint debug = 0;#endif/* * Mountd server for NFS mount protocol as described in: * NFS: Network File System Protocol Specification, RFC1094, Appendix A * The optional arguments are the exports file name * default: _PATH_EXPORTS * and "-n" to allow nonroot mount. */intmain(argc, argv) int argc; char **argv;{ SVCXPRT *transp; int c; while ((c = getopt(argc, argv, "n")) != EOF) switch (c) { case 'n': root_only = 0; break; default: fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); exit(1); }; argc -= optind; argv += optind; grphead = (struct grouplist *)NULL; exphead = (struct exportlist *)NULL; mlhead = (struct mountlist *)NULL; if (argc == 1) { strncpy(exname, *argv, MAXPATHLEN-1); exname[MAXPATHLEN-1] = '\0'; } else strcpy(exname, _PATH_EXPORTS); openlog("mountd", LOG_PID, LOG_DAEMON); if (debug) fprintf(stderr,"Getting export list.\n"); get_exportlist(); if (debug) fprintf(stderr,"Getting mount list.\n"); get_mountlist(); if (debug) fprintf(stderr,"Here we go.\n"); if (debug == 0) { daemon(0, 0); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); } signal(SIGHUP, (void (*) __P((int))) get_exportlist); signal(SIGTERM, (void (*) __P((int))) send_umntall); { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); if (pidfile != NULL) { fprintf(pidfile, "%d\n", getpid()); fclose(pidfile); } } if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { syslog(LOG_ERR, "Can't create socket"); exit(1); } pmap_unset(RPCPROG_MNT, RPCMNT_VER1); if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP)) { syslog(LOG_ERR, "Can't register mount"); exit(1); } svc_run(); syslog(LOG_ERR, "Mountd died"); exit(1);}/* * The mount rpc service */voidmntsrv(rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp;{ struct exportlist *ep; struct dirlist *dp; nfsv2fh_t nfh; struct authunix_parms *ucr; struct stat stb; struct statfs fsb; struct hostent *hp; u_long saddr; char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; int bad = ENOENT, omask, defset; uid_t uid = -2; /* Get authorization */ switch (rqstp->rq_cred.oa_flavor) { case AUTH_UNIX: ucr = (struct authunix_parms *)rqstp->rq_clntcred; uid = ucr->aup_uid; break; case AUTH_NULL: default: break; } saddr = transp->xp_raddr.sin_addr.s_addr; hp = (struct hostent *)NULL; switch (rqstp->rq_proc) { case NULLPROC: if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) syslog(LOG_ERR, "Can't send reply"); return; case RPCMNT_MOUNT: if ((uid != 0 && root_only) || uid == -2) { svcerr_weakauth(transp); return; } if (!svc_getargs(transp, xdr_dir, rpcpath)) { svcerr_decode(transp); return; } /* * Get the real pathname and make sure it is a directory * that exists. */ if (realpath(rpcpath, dirpath) == 0 || stat(dirpath, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR || statfs(dirpath, &fsb) < 0) { chdir("/"); /* Just in case realpath doesn't */ if (debug) fprintf(stderr, "stat failed on %s\n", dirpath); if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) syslog(LOG_ERR, "Can't send reply"); return; } /* Check in the exports list */ omask = sigblock(sigmask(SIGHUP)); ep = ex_search(&fsb.f_fsid); defset = 0; if (ep && (chk_host(ep->ex_defdir, saddr, &defset) || ((dp = dirp_search(ep->ex_dirl, dirpath)) && chk_host(dp, saddr, &defset)) || (defset && scan_tree(ep->ex_defdir, saddr) == 0 && scan_tree(ep->ex_dirl, saddr) == 0))) { /* Get the file handle */ bzero((caddr_t)&nfh, sizeof(nfh)); if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { bad = errno; syslog(LOG_ERR, "Can't get fh for %s", dirpath); if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) syslog(LOG_ERR, "Can't send reply"); sigsetmask(omask); return; } if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) syslog(LOG_ERR, "Can't send reply"); if (hp == NULL) hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); if (hp) add_mlist(hp->h_name, dirpath); else add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); if (debug) fprintf(stderr,"Mount successfull.\n"); } else { bad = EACCES; if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) syslog(LOG_ERR, "Can't send reply"); } sigsetmask(omask); return; case RPCMNT_DUMP: if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) syslog(LOG_ERR, "Can't send reply"); return; case RPCMNT_UMOUNT: if ((uid != 0 && root_only) || uid == -2) { svcerr_weakauth(transp); return; } if (!svc_getargs(transp, xdr_dir, dirpath)) { svcerr_decode(transp); return; } if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) syslog(LOG_ERR, "Can't send reply"); hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); if (hp) del_mlist(hp->h_name, dirpath); del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); return; case RPCMNT_UMNTALL: if ((uid != 0 && root_only) || uid == -2) { svcerr_weakauth(transp); return; } if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) syslog(LOG_ERR, "Can't send reply"); hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); if (hp) del_mlist(hp->h_name, (char *)NULL); del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL); return; case RPCMNT_EXPORT: if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) syslog(LOG_ERR, "Can't send reply"); return; default: svcerr_noproc(transp); return; }}/* * Xdr conversion for a dirpath string */intxdr_dir(xdrsp, dirp) XDR *xdrsp; char *dirp;{ return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));}/* * Xdr routine to generate fhstatus */intxdr_fhs(xdrsp, nfh) XDR *xdrsp; nfsv2fh_t *nfh;{ int ok = 0; if (!xdr_long(xdrsp, &ok)) return (0); return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));}intxdr_mlist(xdrsp, cp) XDR *xdrsp; caddr_t cp;{ struct mountlist *mlp; int true = 1; int false = 0; char *strp; mlp = mlhead; while (mlp) { if (!xdr_bool(xdrsp, &true)) return (0); strp = &mlp->ml_host[0]; if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) return (0); strp = &mlp->ml_dirp[0]; if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) return (0); mlp = mlp->ml_next; } if (!xdr_bool(xdrsp, &false)) return (0); return (1);}/* * Xdr conversion for export list */intxdr_explist(xdrsp, cp) XDR *xdrsp; caddr_t cp;{ struct exportlist *ep; int false = 0; int omask, putdef; omask = sigblock(sigmask(SIGHUP)); ep = exphead; while (ep) { putdef = 0; if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) goto errout; if (ep->ex_defdir && putdef == 0 && put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, &putdef)) goto errout; ep = ep->ex_next; } sigsetmask(omask); if (!xdr_bool(xdrsp, &false)) return (0); return (1);errout: sigsetmask(omask); return (0);}/* * Called from xdr_explist() to traverse the tree and export the * directory paths. */intput_exlist(dp, xdrsp, adp, putdefp) struct dirlist *dp; XDR *xdrsp; struct dirlist *adp; int *putdefp;{ struct grouplist *grp; struct hostlist *hp; int true = 1; int false = 0; int gotalldir = 0; char *strp; if (dp) { if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) return (1); if (!xdr_bool(xdrsp, &true)) return (1); strp = dp->dp_dirp; if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) return (1); if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { gotalldir = 1; *putdefp = 1; } if ((dp->dp_flag & DP_DEFSET) == 0 && (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { hp = dp->dp_hosts; while (hp) { grp = hp->ht_grp; if (grp->gr_type == GT_HOST) { if (!xdr_bool(xdrsp, &true)) return (1); strp = grp->gr_ptr.gt_hostent->h_name; if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) return (1); } else if (grp->gr_type == GT_NET) { if (!xdr_bool(xdrsp, &true)) return (1); strp = grp->gr_ptr.gt_net.nt_name; if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) return (1); } hp = hp->ht_next; if (gotalldir && hp == (struct hostlist *)NULL) { hp = adp->dp_hosts; gotalldir = 0; } } } if (!xdr_bool(xdrsp, &false)) return (1); if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) return (1); } return (0);}#define LINESIZ 10240char line[LINESIZ];FILE *exp_file;/* * Get the export list */voidget_exportlist(){ struct exportlist *ep, *ep2; struct grouplist *grp, *tgrp; struct exportlist **epp; struct dirlist *dirhead; struct statfs fsb, *fsp; struct hostent *hpe; struct ucred anon; char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; /* * First, get rid of the old list */ ep = exphead; while (ep) { ep2 = ep; ep = ep->ex_next; free_exp(ep2); } exphead = (struct exportlist *)NULL; grp = grphead; while (grp) { tgrp = grp; grp = grp->gr_next; free_grp(tgrp); } grphead = (struct grouplist *)NULL; /* * And delete exports that are in the kernel for all local * file systems. * XXX: Should know how to handle all local exportable file systems * instead of just MOUNT_UFS. */ num = getmntinfo(&fsp, MNT_NOWAIT); for (i = 0; i < num; i++) { union { struct ufs_args ua; struct iso_args ia; struct mfs_args ma; } targs; switch (fsp->f_type) { case MOUNT_MFS: case MOUNT_UFS: case MOUNT_CD9660: targs.ua.fspec = NULL; targs.ua.export.ex_flags = MNT_DELEXPORT; if (mount(fsp->f_type, fsp->f_mntonname, fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0) syslog(LOG_ERR, "Can't delete exports for %s", fsp->f_mntonname); } fsp++; } /* * Read in the exports file and build the list, calling * mount() as we go along to push the export rules into the kernel. */ if ((exp_file = fopen(exname, "r")) == NULL) { syslog(LOG_ERR, "Can't open %s", exname); exit(2); } dirhead = (struct dirlist *)NULL; while (get_line()) { if (debug)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -