--- usr.sbin/mountd/mountd.c 2014-08-21 22:03:28.470974123 -0700 +++ mountd.c 2014-10-17 11:17:59.002525308 -0700 @@ -206,7 +206,8 @@ void out_of_mem(void); void parsecred(char *, struct xucred *); int parsesec(char *, struct exportlist *); -int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); +int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int, + struct sockaddr *saddr); void *sa_rawaddr(struct sockaddr *sa, int *nbytes); int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask); @@ -241,6 +242,11 @@ int got_sighup = 0; int xcreated = 0; +int restrict_exports = 0; +#define EXP_VIS 0x00 /* showmount unrestricted */ +#define EXP_HIDDEN 0x01 /* all exports hidden */ +#define EXP_HOST 0x02 /* show only client's exports */ + char *svcport_str = NULL; static int mallocd_svcport = 0; static int *sock_fd; @@ -312,7 +318,7 @@ else close(s); - while ((c = getopt(argc, argv, "2deh:lnop:rS")) != -1) + while ((c = getopt(argc, argv, "2deh:lnop:rSx:")) != -1) switch (c) { case '2': force_v2 = 1; @@ -367,6 +373,14 @@ case 'S': suspend_nfsd = 1; break; + case 'x': + if (strcmp(optarg, "host") == 0) + restrict_exports = EXP_HOST; + else if (strcmp(optarg, "hide") == 0) + restrict_exports = EXP_HIDDEN; + else if (strcmp(optarg, "visible") != 0) + usage(); + break; default: usage(); }; @@ -925,7 +939,7 @@ { fprintf(stderr, "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p ] [-r] " - "[-S] [-h ] [export_file ...]\n"); + "[-S] [-x ] [-h ] [export_file ...]\n"); exit(1); } @@ -1071,12 +1085,22 @@ sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); return; case MOUNTPROC_DUMP: - if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) - syslog(LOG_ERR, "can't send reply"); - else if (dolog) + if (restrict_exports != EXP_HIDDEN) { + if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, + (caddr_t)(!restrict_exports ? NULL : + (lookup_failed ? &numerichost : &host)))) + syslog(LOG_ERR, "can't send reply"); + else if (dolog) + syslog(LOG_NOTICE, + "dump request succeeded from %s", + numerichost); + } else { + if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) + syslog(LOG_ERR, "can't send reply"); syslog(LOG_NOTICE, - "dump request succeeded from %s", + "dump request denied from %s", numerichost); + } return; case MOUNTPROC_UMNT: if (sport >= IPPORT_RESERVED && resvport_only) { @@ -1126,14 +1150,25 @@ numerichost); return; case MOUNTPROC_EXPORT: - if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) - if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, - (caddr_t)NULL)) + if (restrict_exports != EXP_HIDDEN) { + if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, + (caddr_t)(!restrict_exports ? NULL : saddr))) + if (!svc_sendreply(transp, + (xdrproc_t)xdr_explist_brief, + (caddr_t)(!restrict_exports ? NULL : + saddr))) + syslog(LOG_ERR, "can't send reply"); + if (dolog) + syslog(LOG_NOTICE, + "export request succeeded from %s", + numerichost); + } else { + if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) syslog(LOG_ERR, "can't send reply"); - if (dolog) syslog(LOG_NOTICE, - "export request succeeded from %s", + "export request denied from %s", numerichost); + } return; default: svcerr_noproc(transp); @@ -1190,7 +1225,7 @@ } int -xdr_mlist(XDR *xdrsp, caddr_t cp __unused) +xdr_mlist(XDR *xdrsp, caddr_t cp) { struct mountlist *mlp; int true = 1; @@ -1199,6 +1234,13 @@ mlp = mlhead; while (mlp) { + /* restrict to host only if specified in cp */ + if (cp != (caddr_t)NULL) { + if (strcmp(&mlp->ml_host[0], (char *)cp)) { + mlp = mlp->ml_next; + continue; + } + } if (!xdr_bool(xdrsp, &true)) return (0); strp = &mlp->ml_host[0]; @@ -1218,7 +1260,7 @@ * Xdr conversion for export list */ int -xdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) +xdr_explist_common(XDR *xdrsp, caddr_t cp, int brief) { struct exportlist *ep; int false = 0; @@ -1232,11 +1274,11 @@ while (ep) { putdef = 0; if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, - &putdef, brief)) + &putdef, brief, (struct sockaddr *)cp)) goto errout; if (ep->ex_defdir && putdef == 0 && put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, - &putdef, brief)) + &putdef, brief, (struct sockaddr *)cp)) goto errout; ep = ep->ex_next; } @@ -1255,18 +1297,24 @@ */ int put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, - int brief) + int brief, struct sockaddr *saddr) { struct grouplist *grp; struct hostlist *hp; int true = 1; int false = 0; + int defset, hostset; int gotalldir = 0; char *strp; if (dp) { - if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) + if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief, saddr)) return (1); + + if (saddr != NULL && + !chk_host(dp, saddr, &defset, &hostset, NULL, NULL)) + goto skipentry; + if (!xdr_bool(xdrsp, &true)) return (1); strp = dp->dp_dirp; @@ -1311,7 +1359,9 @@ } if (!xdr_bool(xdrsp, &false)) return (1); - if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) + +skipentry: + if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief, saddr)) return (1); } return (0);