summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorMarcel Telka <marcel.telka@nexenta.com>2015-10-15 09:00:58 +0200
committerRobert Mustacchi <rm@joyent.com>2015-11-02 17:56:05 -0800
commita9685eaab1313767d1d4dac672c3a468519aa899 (patch)
tree95722bb8a0406610d6856901bb98710a9787c80e /usr/src
parent33e8313d921ed710d7c5957cea98e220a663a1d5 (diff)
downloadillumos-joyent-a9685eaab1313767d1d4dac672c3a468519aa899.tar.gz
6321 mountd: The IP to name translation is usually not needed in nfsauth_access()
Reviewed by: Gordon Ross <gordon.ross@nexenta.com> Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fs.d/nfs/mountd/mountd.c580
-rw-r--r--usr/src/cmd/fs.d/nfs/mountd/mountd.h31
-rw-r--r--usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c33
-rw-r--r--usr/src/cmd/fs.d/nfs/mountd/nfsauth.c67
4 files changed, 322 insertions, 389 deletions
diff --git a/usr/src/cmd/fs.d/nfs/mountd/mountd.c b/usr/src/cmd/fs.d/nfs/mountd/mountd.c
index 50180d3815..150455f3d9 100644
--- a/usr/src/cmd/fs.d/nfs/mountd/mountd.c
+++ b/usr/src/cmd/fs.d/nfs/mountd/mountd.c
@@ -102,20 +102,12 @@ static mutex_t logging_queue_lock;
static cond_t logging_queue_cv;
static share_t *find_lofsentry(char *, int *);
-static int getclientsnames_lazy(char *, struct netbuf **,
- struct nd_hostservlist **);
-static int getclientsnames(SVCXPRT *, struct netbuf **,
- struct nd_hostservlist **);
-static int getclientsflavors_old(share_t *, SVCXPRT *, struct netbuf **,
- struct nd_hostservlist **, int *);
-static int getclientsflavors_new(share_t *, SVCXPRT *, struct netbuf **,
- struct nd_hostservlist **, int *);
-static int check_client_old(share_t *, SVCXPRT *, struct netbuf **,
- struct nd_hostservlist **, int, uid_t, gid_t, uint_t, gid_t *, uid_t *,
- gid_t *, uint_t *, gid_t **);
-static int check_client_new(share_t *, SVCXPRT *, struct netbuf **,
- struct nd_hostservlist **, int, uid_t, gid_t, uint_t, gid_t *, uid_t *,
- gid_t *i, uint_t *, gid_t **);
+static int getclientsflavors_old(share_t *, struct cln *, int *);
+static int getclientsflavors_new(share_t *, struct cln *, int *);
+static int check_client_old(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
+ gid_t *, uid_t *, gid_t *, uint_t *, gid_t **);
+static int check_client_new(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
+ gid_t *, uid_t *, gid_t *i, uint_t *, gid_t **);
static void mnt(struct svc_req *, SVCXPRT *);
static void mnt_pathconf(struct svc_req *);
static int mount(struct svc_req *r);
@@ -301,16 +293,13 @@ do_logging_queue(logging_data *lq)
int cleared = 0;
char *host;
- struct nd_hostservlist *clnames;
-
while (lq) {
+ struct cln cln;
+
if (lq->ld_host == NULL) {
DTRACE_PROBE(mountd, name_by_lazy);
- if (getclientsnames_lazy(lq->ld_netid,
- &lq->ld_nb, &clnames) != 0)
- host = NULL;
- else
- host = clnames->h_hostservs[0].h_host;
+ cln_init_lazy(&cln, lq->ld_netid, lq->ld_nb);
+ host = cln_gethost(&cln);
} else
host = lq->ld_host;
@@ -320,8 +309,8 @@ do_logging_queue(logging_data *lq)
if (lq->ld_rpath)
mntlist_new(host, lq->ld_rpath);
- if (lq->ld_host != host)
- netdir_free(clnames, ND_HOSTSERVLIST);
+ if (lq->ld_host == NULL)
+ cln_fini(&cln);
free_logging_data(lq);
cleared++;
@@ -765,164 +754,38 @@ mnt(struct svc_req *rqstp, SVCXPRT *transp)
}
}
-/* Set up anonymous client */
-
-struct nd_hostservlist *
-anon_client(char *host)
+void
+log_cant_reply_cln(struct cln *cln)
{
- struct nd_hostservlist *anon_hsl;
- struct nd_hostserv *anon_hs;
-
- anon_hsl = malloc(sizeof (*anon_hsl));
- if (anon_hsl == NULL)
- return (NULL);
+ int saverrno;
+ char *host;
- anon_hs = malloc(sizeof (*anon_hs));
- if (anon_hs == NULL) {
- free(anon_hsl);
- return (NULL);
- }
+ saverrno = errno; /* save error code */
+ host = cln_gethost(cln);
if (host == NULL)
- anon_hs->h_host = strdup("(anon)");
- else
- anon_hs->h_host = strdup(host);
-
- if (anon_hs->h_host == NULL) {
- free(anon_hs);
- free(anon_hsl);
- return (NULL);
- }
- anon_hs->h_serv = '\0';
-
- anon_hsl->h_cnt = 1;
- anon_hsl->h_hostservs = anon_hs;
-
- return (anon_hsl);
-}
-
-static int
-getclientsnames_common(struct netconfig *nconf, struct netbuf **nbuf,
- struct nd_hostservlist **serv)
-{
- char host[MAXIPADDRLEN];
-
- assert(*nbuf != NULL);
-
- /*
- * Use the this API instead of the netdir_getbyaddr()
- * to avoid service lookup.
- */
- if (__netdir_getbyaddr_nosrv(nconf, serv, *nbuf) != 0) {
- if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
- struct sockaddr_in *sa;
-
- /* LINTED pointer alignment */
- sa = (struct sockaddr_in *)((*nbuf)->buf);
- (void) inet_ntoa_r(sa->sin_addr, host);
- } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
- struct sockaddr_in6 *sa;
-
- /* LINTED pointer alignment */
- sa = (struct sockaddr_in6 *)((*nbuf)->buf);
- (void) inet_ntop(AF_INET6, sa->sin6_addr.s6_addr,
- host, INET6_ADDRSTRLEN);
- } else {
- syslog(LOG_ERR, gettext(
- "Client's address is neither IPv4 nor IPv6"));
- return (EINVAL);
- }
-
- *serv = anon_client(host);
- if (*serv == NULL)
- return (ENOMEM);
- }
-
- assert(*serv != NULL);
- return (0);
-}
-
-/*
- * Get the client's hostname from the copy of the
- * relevant transport handle parts.
- * If the name is not available then return "(anon)".
- */
-static int
-getclientsnames_lazy(char *netid, struct netbuf **nbuf,
- struct nd_hostservlist **serv)
-{
- struct netconfig *nconf;
- int rc;
-
- nconf = getnetconfigent(netid);
- if (nconf == NULL) {
- syslog(LOG_ERR, "%s: getnetconfigent failed", netid);
- *serv = anon_client(NULL);
- if (*serv == NULL)
- return (ENOMEM);
- return (0);
- }
-
- rc = getclientsnames_common(nconf, nbuf, serv);
- freenetconfigent(nconf);
- return (rc);
-}
-
-/*
- * Get the client's hostname from the transport handle.
- * If the name is not available then return "(anon)".
- */
-int
-getclientsnames(SVCXPRT *transp, struct netbuf **nbuf,
- struct nd_hostservlist **serv)
-{
- struct netconfig *nconf;
- int rc;
-
- nconf = getnetconfigent(transp->xp_netid);
- if (nconf == NULL) {
- syslog(LOG_ERR, "%s: getnetconfigent failed",
- transp->xp_netid);
- *serv = anon_client(NULL);
- if (*serv == NULL)
- return (ENOMEM);
- return (0);
- }
-
- *nbuf = svc_getrpccaller(transp);
- if (*nbuf == NULL) {
- freenetconfigent(nconf);
- *serv = anon_client(NULL);
- if (*serv == NULL)
- return (ENOMEM);
- return (0);
- }
+ return;
- rc = getclientsnames_common(nconf, nbuf, serv);
- freenetconfigent(nconf);
- return (rc);
+ errno = saverrno;
+ if (errno == 0)
+ syslog(LOG_ERR, "couldn't send reply to %s", host);
+ else
+ syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
}
void
log_cant_reply(SVCXPRT *transp)
{
int saverrno;
- struct nd_hostservlist *clnames = NULL;
- char *host;
- struct netbuf *nb;
+ struct cln cln;
saverrno = errno; /* save error code */
- if (getclientsnames(transp, &nb, &clnames) != 0)
- return;
- host = clnames->h_hostservs->h_host;
-
+ cln_init(&cln, transp);
errno = saverrno;
- if (errno == 0)
- syslog(LOG_ERR, "couldn't send reply to %s", host);
- else
- syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
- netdir_free(clnames, ND_HOSTSERVLIST);
+ log_cant_reply_cln(&cln);
+
+ cln_fini(&cln);
}
/*
@@ -1030,8 +893,7 @@ checkrootmount(share_t *sh, char *rpath)
* otherwise EACCES.
*/
static int
-mount_enoent_error(SVCXPRT *transp, char *path, char *rpath,
- struct nd_hostservlist **clnames, struct netbuf **nb, int *flavor_list)
+mount_enoent_error(struct cln *cln, char *path, char *rpath, int *flavor_list)
{
char *checkpath, *dp;
share_t *sh = NULL;
@@ -1074,11 +936,11 @@ mount_enoent_error(SVCXPRT *transp, char *path, char *rpath,
* Check permissions in mount table.
*/
if (newopts(sh->sh_opts))
- flavor_count = getclientsflavors_new(sh,
- transp, nb, clnames, flavor_list);
+ flavor_count = getclientsflavors_new(sh, cln,
+ flavor_list);
else
- flavor_count = getclientsflavors_old(sh,
- transp, nb, clnames, flavor_list);
+ flavor_count = getclientsflavors_old(sh, cln,
+ flavor_list);
if (flavor_count != 0) {
/*
* Found entry in table and
@@ -1202,6 +1064,140 @@ cleanup:
return (FALSE);
}
+
+#define CLN_CLNAMES (1 << 0)
+#define CLN_HOST (1 << 1)
+
+static void
+cln_init_common(struct cln *cln, SVCXPRT *transp, char *netid,
+ struct netbuf *nbuf)
+{
+ if ((cln->transp = transp) != NULL) {
+ assert(netid == NULL && nbuf == NULL);
+ cln->netid = transp->xp_netid;
+ cln->nbuf = svc_getrpccaller(transp);
+ } else {
+ cln->netid = netid;
+ cln->nbuf = nbuf;
+ }
+
+ cln->nconf = NULL;
+ cln->clnames = NULL;
+ cln->host = NULL;
+
+ cln->flags = 0;
+}
+
+void
+cln_init(struct cln *cln, SVCXPRT *transp)
+{
+ cln_init_common(cln, transp, NULL, NULL);
+}
+
+void
+cln_init_lazy(struct cln *cln, char *netid, struct netbuf *nbuf)
+{
+ cln_init_common(cln, NULL, netid, nbuf);
+}
+
+void
+cln_fini(struct cln *cln)
+{
+ if (cln->nconf != NULL)
+ freenetconfigent(cln->nconf);
+
+ if (cln->clnames != NULL)
+ netdir_free(cln->clnames, ND_HOSTSERVLIST);
+
+ free(cln->host);
+}
+
+struct netbuf *
+cln_getnbuf(struct cln *cln)
+{
+ return (cln->nbuf);
+}
+
+struct nd_hostservlist *
+cln_getclientsnames(struct cln *cln)
+{
+ if ((cln->flags & CLN_CLNAMES) == 0) {
+ /*
+ * nconf is not needed if we do not have nbuf (see
+ * cln_gethost() too), so we check for nbuf and in a case it is
+ * NULL we do not try to get nconf.
+ */
+ if (cln->netid != NULL && cln->nbuf != NULL) {
+ cln->nconf = getnetconfigent(cln->netid);
+ if (cln->nconf == NULL)
+ syslog(LOG_ERR, "%s: getnetconfigent failed",
+ cln->netid);
+ }
+
+ if (cln->nconf != NULL && cln->nbuf != NULL)
+ (void) __netdir_getbyaddr_nosrv(cln->nconf,
+ &cln->clnames, cln->nbuf);
+
+ cln->flags |= CLN_CLNAMES;
+ }
+
+ return (cln->clnames);
+}
+
+/*
+ * Return B_TRUE if the host is already available at no cost
+ */
+boolean_t
+cln_havehost(struct cln *cln)
+{
+ return ((cln->flags & (CLN_CLNAMES | CLN_HOST)) != 0);
+}
+
+char *
+cln_gethost(struct cln *cln)
+{
+ if (cln_getclientsnames(cln) != NULL)
+ return (cln->clnames->h_hostservs[0].h_host);
+
+ if ((cln->flags & CLN_HOST) == 0) {
+ if (cln->nconf == NULL || cln->nbuf == NULL) {
+ cln->host = strdup("(anon)");
+ } else {
+ char host[MAXIPADDRLEN];
+
+ if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) {
+ struct sockaddr_in *sa;
+
+ /* LINTED pointer alignment */
+ sa = (struct sockaddr_in *)(cln->nbuf->buf);
+ (void) inet_ntoa_r(sa->sin_addr, host);
+
+ cln->host = strdup(host);
+ } else if (strcmp(cln->nconf->nc_protofmly,
+ NC_INET6) == 0) {
+ struct sockaddr_in6 *sa;
+
+ /* LINTED pointer alignment */
+ sa = (struct sockaddr_in6 *)(cln->nbuf->buf);
+ (void) inet_ntop(AF_INET6,
+ sa->sin6_addr.s6_addr,
+ host, INET6_ADDRSTRLEN);
+
+ cln->host = strdup(host);
+ } else {
+ syslog(LOG_ERR, gettext("Client's address is "
+ "neither IPv4 nor IPv6"));
+
+ cln->host = strdup("(anon)");
+ }
+ }
+
+ cln->flags |= CLN_HOST;
+ }
+
+ return (cln->host);
+}
+
/*
* Check mount requests, add to mounted list if ok
*/
@@ -1216,12 +1212,11 @@ mount(struct svc_req *rqstp)
int len = FHSIZE3;
char *path, rpath[MAXPATHLEN];
share_t *sh = NULL;
- struct nd_hostservlist *clnames = NULL;
+ struct cln cln;
char *host = NULL;
int error = 0, lofs_tried = 0, enqueued;
int flavor_list[MAX_FLAVORS];
int flavor_count;
- struct netbuf *nb = NULL;
ucred_t *uc = NULL;
int audit_status;
@@ -1235,6 +1230,8 @@ mount(struct svc_req *rqstp)
return (EACCES);
}
+ cln_init(&cln, transp);
+
/*
* Put off getting the name for the client until we
* need it. This is a performance gain. If we are logging,
@@ -1244,7 +1241,7 @@ mount(struct svc_req *rqstp)
*/
if (verbose) {
DTRACE_PROBE(mountd, name_by_verbose);
- if (getclientsnames(transp, &nb, &clnames) != 0) {
+ if ((host = cln_gethost(&cln)) == NULL) {
/*
* We failed to get a name for the client, even
* 'anon', probably because we ran out of memory.
@@ -1254,7 +1251,6 @@ mount(struct svc_req *rqstp)
error = EACCES;
goto reply;
}
- host = clnames->h_hostservs[0].h_host;
}
/*
@@ -1295,8 +1291,8 @@ mount(struct svc_req *rqstp)
syslog(LOG_ERR,
"mount request: realpath: %s: %m", path);
if (error == ENOENT)
- error = mount_enoent_error(transp, path, rpath,
- &clnames, &nb, flavor_list);
+ error = mount_enoent_error(&cln, path, rpath,
+ flavor_list);
goto reply;
}
@@ -1316,14 +1312,9 @@ mount(struct svc_req *rqstp)
}
if (newopts(sh->sh_opts))
- flavor_count = getclientsflavors_new(sh, transp, &nb, &clnames,
- flavor_list);
+ flavor_count = getclientsflavors_new(sh, &cln, flavor_list);
else
- flavor_count = getclientsflavors_old(sh, transp, &nb, &clnames,
- flavor_list);
-
- if (clnames)
- host = clnames->h_hostservs[0].h_host;
+ flavor_count = getclientsflavors_old(sh, &cln, flavor_list);
if (flavor_count == 0) {
error = EACCES;
@@ -1442,7 +1433,7 @@ reply:
fhs.fhs_status = error;
if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs))
- log_cant_reply(transp);
+ log_cant_reply_cln(&cln);
audit_status = fhs.fhs_status;
break;
@@ -1459,12 +1450,15 @@ reply:
mountres3.fhs_status = error;
if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
- log_cant_reply(transp);
+ log_cant_reply_cln(&cln);
audit_status = mountres3.fhs_status;
break;
}
+ if (cln_havehost(&cln))
+ host = cln_gethost(&cln);
+
if (verbose)
syslog(LOG_NOTICE, "MOUNT: %s %s %s",
(host == NULL) ? "unknown host" : host,
@@ -1479,8 +1473,7 @@ reply:
if (enqueued == FALSE) {
if (host == NULL) {
DTRACE_PROBE(mountd, name_by_in_thread);
- if (getclientsnames(transp, &nb, &clnames) == 0)
- host = clnames->h_hostservs[0].h_host;
+ host = cln_gethost(&cln);
}
DTRACE_PROBE(mountd, logged_in_thread);
@@ -1494,7 +1487,8 @@ reply:
if (sh)
sharefree(sh);
- netdir_free(clnames, ND_HOSTSERVLIST);
+
+ cln_fini(&cln);
return (error);
}
@@ -1791,13 +1785,13 @@ done:
* not distinguished syntactically. We check for hosts first because
* it's cheaper, then try netgroups.
*
- * If pnb and pclnames are NULL, it means that we have to use transp
- * to resolve client IP address to hostname. If they aren't NULL
- * then transp argument won't be used and can be NULL.
+ * Return values:
+ * 1 - access is granted
+ * 0 - access is denied
+ * -1 - an error occured
*/
int
-in_access_list(SVCXPRT *transp, struct netbuf **pnb,
- struct nd_hostservlist **pclnames,
+in_access_list(struct cln *cln,
char *access_list) /* N.B. we clobber this "input" parameter */
{
char addr[INET_ADDRSTRLEN];
@@ -1805,45 +1799,29 @@ in_access_list(SVCXPRT *transp, struct netbuf **pnb,
int nentries = 0;
char *cstr = access_list;
char *gr = access_list;
- char *host;
- int off;
int i;
int response;
- int sbr = 0;
- struct nd_hostservlist *clnames;
- struct netent n, *np;
+ struct netbuf *pnb;
+ struct nd_hostservlist *clnames = NULL;
/* If no access list - then it's unrestricted */
if (access_list == NULL || *access_list == '\0')
return (1);
- assert(transp != NULL || (*pnb != NULL && *pclnames != NULL));
-
- /* Get client address if it wasn't provided */
- if (*pnb == NULL)
- /* Don't grant access if client address isn't known */
- if ((*pnb = svc_getrpccaller(transp)) == NULL)
- return (0);
-
- /* Try to lookup client hostname if it wasn't provided */
- if (*pclnames == NULL)
- getclientsnames(transp, pnb, pclnames);
- clnames = *pclnames;
+ if ((pnb = cln_getnbuf(cln)) == NULL)
+ return (-1);
for (;;) {
- if ((cstr = strpbrk(cstr, "[]:")) != NULL) {
- switch (*cstr) {
- case '[':
- case ']':
- sbr = !sbr;
+ if ((cstr = strpbrk(cstr, "[:")) != NULL) {
+ if (*cstr == ':') {
+ *cstr = '\0';
+ } else {
+ assert(*cstr == '[');
+ cstr = strchr(cstr + 1, ']');
+ if (cstr == NULL)
+ return (-1);
cstr++;
continue;
- case ':':
- if (sbr) {
- cstr++;
- continue;
- }
- *cstr = '\0';
}
}
@@ -1867,6 +1845,8 @@ in_access_list(SVCXPRT *transp, struct netbuf **pnb,
/* Netname support */
if (!isdigit(*gr) && *gr != '[') {
+ struct netent n, *np;
+
if ((np = getnetbyname_r(gr, &n, buff,
sizeof (buff))) != NULL &&
np->n_net != 0) {
@@ -1876,38 +1856,27 @@ in_access_list(SVCXPRT *transp, struct netbuf **pnb,
if (inet_ntop(AF_INET, &np->n_net, addr,
INET_ADDRSTRLEN) == NULL)
break;
- if (inet_matchaddr((*pnb)->buf, addr))
+ if (inet_matchaddr(pnb->buf, addr))
return (response);
}
} else {
- if (inet_matchaddr((*pnb)->buf, gr))
+ if (inet_matchaddr(pnb->buf, gr))
return (response);
}
- if (cstr == NULL)
- break;
-
- gr = ++cstr;
-
- continue;
+ goto next;
}
/*
* No other checks can be performed if client address
* can't be resolved.
*/
- if (clnames == NULL) {
- if (cstr == NULL)
- break;
-
- gr = ++cstr;
-
- continue;
- }
+ if ((clnames = cln_getclientsnames(cln)) == NULL)
+ goto next;
/* Otherwise loop through all client hostname aliases */
for (i = 0; i < clnames->h_cnt; i++) {
- host = clnames->h_hostservs[i].h_host;
+ char *host = clnames->h_hostservs[i].h_host;
/*
* If the list name begins with a dot then
@@ -1920,7 +1889,7 @@ in_access_list(SVCXPRT *transp, struct netbuf **pnb,
if (strchr(host, '.') == NULL)
return (response);
} else {
- off = strlen(host) - strlen(gr);
+ int off = strlen(host) - strlen(gr);
if (off > 0 &&
strcasecmp(host + off, gr) == 0) {
return (response);
@@ -1935,6 +1904,7 @@ in_access_list(SVCXPRT *transp, struct netbuf **pnb,
nentries++;
+next:
if (cstr == NULL)
break;
@@ -2032,8 +2002,7 @@ newopts(char *opts)
* default is that access is granted.
*/
static int
-getclientsflavors_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
- struct nd_hostservlist **clnames, int *flavors)
+getclientsflavors_old(share_t *sh, struct cln *cln, int *flavors)
{
char *opts, *p, *val;
boolean_t ok = B_FALSE;
@@ -2059,13 +2028,13 @@ getclientsflavors_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
case OPT_RO:
case OPT_RW:
defaultaccess = 0;
- if (in_access_list(transp, nb, clnames, val))
- ok++;
+ if (in_access_list(cln, val) > 0)
+ ok = B_TRUE;
break;
case OPT_NONE:
defaultaccess = 0;
- if (in_access_list(transp, nb, clnames, val))
+ if (in_access_list(cln, val) > 0)
reject = B_TRUE;
}
}
@@ -2074,7 +2043,7 @@ getclientsflavors_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
/* none takes precedence over everything else */
if (reject)
- ok = B_TRUE;
+ ok = B_FALSE;
return (defaultaccess || ok);
}
@@ -2097,13 +2066,13 @@ getclientsflavors_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
* version 3 of the mount protocol.
*/
static int
-getclientsflavors_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
- struct nd_hostservlist **clnames, int *flavors)
+getclientsflavors_new(share_t *sh, struct cln *cln, int *flavors)
{
char *opts, *p, *val;
char *lasts;
char *f;
- boolean_t access_ok;
+ boolean_t defaultaccess = B_TRUE; /* default access is rw */
+ boolean_t access_ok = B_FALSE;
int count, c;
boolean_t reject = B_FALSE;
@@ -2115,43 +2084,43 @@ getclientsflavors_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
p = opts;
count = c = 0;
- /* default access is rw */
- access_ok = B_TRUE;
while (*p) {
switch (getsubopt(&p, optlist, &val)) {
case OPT_SEC:
+ if (reject)
+ access_ok = B_FALSE;
+
/*
* Before a new sec=xxx option, check if we need
* to move the c index back to the previous count.
*/
- if (!access_ok) {
+ if (!defaultaccess && !access_ok) {
c = count;
}
/* get all the sec=f1[:f2] flavors */
- while ((f = strtok_r(val, ":", &lasts))
- != NULL) {
+ while ((f = strtok_r(val, ":", &lasts)) != NULL) {
flavors[c++] = map_flavor(f);
val = NULL;
}
/* for a new sec=xxx option, default is rw access */
- access_ok = B_TRUE;
+ defaultaccess = B_TRUE;
+ access_ok = B_FALSE;
+ reject = B_FALSE;
break;
case OPT_RO:
case OPT_RW:
- if (in_access_list(transp, nb, clnames, val)) {
- count = c;
+ defaultaccess = B_FALSE;
+ if (in_access_list(cln, val) > 0)
access_ok = B_TRUE;
- } else {
- access_ok = B_FALSE;
- }
break;
case OPT_NONE:
- if (in_access_list(transp, nb, clnames, val))
+ defaultaccess = B_FALSE;
+ if (in_access_list(cln, val) > 0)
reject = B_TRUE; /* none overides rw/ro */
break;
}
@@ -2160,7 +2129,7 @@ getclientsflavors_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
if (reject)
access_ok = B_FALSE;
- if (!access_ok)
+ if (!defaultaccess && !access_ok)
c = count;
free(opts);
@@ -2178,19 +2147,18 @@ getclientsflavors_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
* flavor. Other flavors are values of the new "sec=" option.
*/
int
-check_client(share_t *sh, struct netbuf *nb,
- struct nd_hostservlist *clnames, int flavor, uid_t clnt_uid, gid_t clnt_gid,
- uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid, gid_t *srv_gid,
- uint_t *srv_ngids, gid_t **srv_gids)
+check_client(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
+ gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
+ gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
{
if (newopts(sh->sh_opts))
- return (check_client_new(sh, NULL, &nb, &clnames, flavor,
- clnt_uid, clnt_gid, clnt_ngids, clnt_gids, srv_uid, srv_gid,
- srv_ngids, srv_gids));
+ return (check_client_new(sh, cln, flavor, clnt_uid, clnt_gid,
+ clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
+ srv_gids));
else
- return (check_client_old(sh, NULL, &nb, &clnames, flavor,
- clnt_uid, clnt_gid, clnt_ngids, clnt_gids, srv_uid, srv_gid,
- srv_ngids, srv_gids));
+ return (check_client_old(sh, cln, flavor, clnt_uid, clnt_gid,
+ clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
+ srv_gids));
}
extern int _getgroupsbymember(const char *, gid_t[], int, int);
@@ -2313,8 +2281,7 @@ get_gid(char *value, gid_t *gid)
}
static int
-check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
- struct nd_hostservlist **clnames, int flavor, uid_t clnt_uid,
+check_client_old(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
{
@@ -2363,7 +2330,7 @@ check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
list++;
if (val != NULL)
ro_val++;
- if (in_access_list(transp, nb, clnames, val))
+ if (in_access_list(cln, val) > 0)
perm |= NFSAUTH_RO;
break;
@@ -2371,7 +2338,7 @@ check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
list++;
if (val != NULL)
rw_val++;
- if (in_access_list(transp, nb, clnames, val))
+ if (in_access_list(cln, val) > 0)
perm |= NFSAUTH_RW;
break;
@@ -2390,7 +2357,7 @@ check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
if (clnt_uid != 0)
break;
- if (in_access_list(transp, nb, clnames, val)) {
+ if (in_access_list(cln, val) > 0) {
perm |= NFSAUTH_ROOT;
perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
map_deny = B_FALSE;
@@ -2410,7 +2377,7 @@ check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
* to this share at all. This option behaves
* more like "root" than either "rw" or "ro".
*/
- if (in_access_list(transp, nb, clnames, val))
+ if (in_access_list(cln, val) > 0)
perm |= NFSAUTH_DENIED;
break;
@@ -2469,7 +2436,7 @@ check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
break;
}
- if (in_access_list(transp, nb, clnames, al)) {
+ if (in_access_list(cln, al) > 0) {
*srv_uid = srv;
perm |= NFSAUTH_UIDMAP;
@@ -2542,7 +2509,7 @@ check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
break;
}
- if (in_access_list(transp, nb, clnames, al)) {
+ if (in_access_list(cln, al) > 0) {
*srv_gid = srv;
perm |= NFSAUTH_GIDMAP;
@@ -2627,15 +2594,13 @@ check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
* return TRUE to indicate that this "flavor" is a wrong sec.
*/
static bool_t
-is_wrongsec(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
- struct nd_hostservlist **clnames, int flavor)
+is_wrongsec(share_t *sh, struct cln *cln, int flavor)
{
int flavor_list[MAX_FLAVORS];
int flavor_count, i;
/* get the flavor list that the client has access with */
- flavor_count = getclientsflavors_new(sh, transp, nb,
- clnames, flavor_list);
+ flavor_count = getclientsflavors_new(sh, cln, flavor_list);
if (flavor_count == 0)
return (FALSE);
@@ -2673,8 +2638,7 @@ is_wrongsec(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
*/
static int
-check_client_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
- struct nd_hostservlist **clnames, int flavor, uid_t clnt_uid,
+check_client_new(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
{
@@ -2729,7 +2693,7 @@ check_client_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
list++;
if (val != NULL)
ro_val++;
- if (in_access_list(transp, nb, clnames, val))
+ if (in_access_list(cln, val) > 0)
perm |= NFSAUTH_RO;
break;
@@ -2740,7 +2704,7 @@ check_client_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
list++;
if (val != NULL)
rw_val++;
- if (in_access_list(transp, nb, clnames, val))
+ if (in_access_list(cln, val) > 0)
perm |= NFSAUTH_RW;
break;
@@ -2762,7 +2726,7 @@ check_client_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
if (clnt_uid != 0)
break;
- if (in_access_list(transp, nb, clnames, val)) {
+ if (in_access_list(cln, val) > 0) {
perm |= NFSAUTH_ROOT;
perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
map_deny = B_FALSE;
@@ -2782,7 +2746,7 @@ check_client_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
* to this share at all. This option behaves
* more like "root" than either "rw" or "ro".
*/
- if (in_access_list(transp, nb, clnames, val))
+ if (in_access_list(cln, val) > 0)
perm |= NFSAUTH_DENIED;
break;
@@ -2841,7 +2805,7 @@ check_client_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
break;
}
- if (in_access_list(transp, nb, clnames, al)) {
+ if (in_access_list(cln, al) > 0) {
*srv_uid = srv;
perm |= NFSAUTH_UIDMAP;
@@ -2914,7 +2878,7 @@ check_client_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
break;
}
- if (in_access_list(transp, nb, clnames, al)) {
+ if (in_access_list(cln, al) > 0) {
*srv_gid = srv;
perm |= NFSAUTH_GIDMAP;
@@ -2967,7 +2931,7 @@ done:
* If not, return NFSAUTH_DENIED.
*/
if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) {
- if (is_wrongsec(sh, transp, nb, clnames, flavor))
+ if (is_wrongsec(sh, cln, flavor))
perm |= NFSAUTH_WRONGSEC;
else
perm |= NFSAUTH_DENIED;
@@ -3137,9 +3101,8 @@ umount(struct svc_req *rqstp)
{
char *host, *path, *remove_path;
char rpath[MAXPATHLEN];
- struct nd_hostservlist *clnames = NULL;
SVCXPRT *transp;
- struct netbuf *nb;
+ struct cln cln;
transp = rqstp->rq_xprt;
path = NULL;
@@ -3147,11 +3110,15 @@ umount(struct svc_req *rqstp)
svcerr_decode(transp);
return;
}
+
+ cln_init(&cln, transp);
+
errno = 0;
if (!svc_sendreply(transp, xdr_void, (char *)NULL))
- log_cant_reply(transp);
+ log_cant_reply_cln(&cln);
- if (getclientsnames(transp, &nb, &clnames) != 0) {
+ host = cln_gethost(&cln);
+ if (host == NULL) {
/*
* Without the hostname we can't do audit or delete
* this host from the mount entries.
@@ -3159,7 +3126,6 @@ umount(struct svc_req *rqstp)
svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
return;
}
- host = clnames->h_hostservs[0].h_host;
if (verbose)
syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
@@ -3175,8 +3141,9 @@ umount(struct svc_req *rqstp)
mntlist_delete(host, remove_path); /* remove from mount list */
+ cln_fini(&cln);
+
svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
- netdir_free(clnames, ND_HOSTSERVLIST);
}
/*
@@ -3185,10 +3152,9 @@ umount(struct svc_req *rqstp)
static void
umountall(struct svc_req *rqstp)
{
- struct nd_hostservlist *clnames = NULL;
SVCXPRT *transp;
char *host;
- struct netbuf *nb;
+ struct cln cln;
transp = rqstp->rq_xprt;
if (!svc_getargs(transp, xdr_void, NULL)) {
@@ -3202,13 +3168,15 @@ umountall(struct svc_req *rqstp)
* on the net blasting the requester with a response.
*/
svcerr_systemerr(transp);
- if (getclientsnames(transp, &nb, &clnames) != 0) {
+
+ cln_init(&cln, transp);
+
+ host = cln_gethost(&cln);
+ if (host == NULL) {
/* Can't do anything without the name of the client */
return;
}
- host = clnames->h_hostservs[0].h_host;
-
/*
* Remove all hosts entries from mount list
*/
@@ -3217,7 +3185,7 @@ umountall(struct svc_req *rqstp)
if (verbose)
syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
- netdir_free(clnames, ND_HOSTSERVLIST);
+ cln_fini(&cln);
}
void *
diff --git a/usr/src/cmd/fs.d/nfs/mountd/mountd.h b/usr/src/cmd/fs.d/nfs/mountd/mountd.h
index 1bc7b088a7..85a506e1b9 100644
--- a/usr/src/cmd/fs.d/nfs/mountd/mountd.h
+++ b/usr/src/cmd/fs.d/nfs/mountd/mountd.h
@@ -60,18 +60,35 @@ extern struct sh_list *share_list;
extern rwlock_t sharetab_lock;
extern void check_sharetab(void);
+struct cln;
extern void log_cant_reply(SVCXPRT *);
+extern void log_cant_reply_cln(struct cln *);
extern void *exmalloc(size_t);
extern struct share *findentry(char *);
-extern int check_client(struct share *, struct netbuf *,
- struct nd_hostservlist *, int, uid_t, gid_t, uint_t, gid_t *, uid_t *,
- gid_t *, uint_t *, gid_t **);
-extern struct nd_hostservlist *anon_client(char *host);
-
-extern int in_access_list(SVCXPRT *, struct netbuf **,
- struct nd_hostservlist **, char *);
+extern int check_client(struct share *, struct cln *, int, uid_t, gid_t, uint_t,
+ gid_t *, uid_t *, gid_t *, uint_t *, gid_t **);
+
+extern int in_access_list(struct cln *, char *);
+
+struct cln {
+ SVCXPRT *transp;
+ char *netid;
+ struct netconfig *nconf;
+ struct netbuf *nbuf;
+ struct nd_hostservlist *clnames;
+ char *host;
+ int flags;
+};
+
+extern void cln_init(struct cln *, SVCXPRT *);
+extern void cln_init_lazy(struct cln *, char *, struct netbuf *);
+extern void cln_fini(struct cln *);
+extern struct netbuf *cln_getnbuf(struct cln *);
+extern struct nd_hostservlist *cln_getclientsnames(struct cln *);
+extern boolean_t cln_havehost(struct cln *);
+extern char *cln_gethost(struct cln *);
/*
* These functions are defined here due to the fact
diff --git a/usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c b/usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c
index fba58fa821..b92a862d91 100644
--- a/usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c
+++ b/usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c
@@ -101,42 +101,29 @@ charmap_search(struct netbuf *nbuf, char *opts)
char *next;
char *name;
char *result = NULL;
- struct netconfig *nconf;
- struct nd_hostservlist *hl = NULL;
+ char *netid;
struct sockaddr *sa;
+ struct cln cln;
+
sa = (struct sockaddr *)nbuf->buf;
switch (sa->sa_family) {
case AF_INET:
- nconf = getnetconfigent("tcp");
+ netid = "tcp";
break;
case AF_INET6:
- nconf = getnetconfigent("tcp6");
+ netid = "tcp6";
break;
default:
return (NULL);
}
- if (nconf == NULL) {
- return (NULL);
- }
-
- /*
- * Use the this API instead of the netdir_getbyaddr()
- * to avoid service lookup.
- */
- if (__netdir_getbyaddr_nosrv(nconf, &hl, nbuf)) {
- syslog(LOG_ERR, "netdir: %s\n", netdir_sperror());
- freenetconfigent(nconf);
- return (NULL);
- }
-
copts = strdup(opts);
- if (copts == NULL) {
- freenetconfigent(nconf);
+ if (copts == NULL)
return (NULL);
- }
+
+ cln_init_lazy(&cln, netid, nbuf);
next = copts;
while (*next != '\0') {
@@ -152,7 +139,7 @@ charmap_search(struct netbuf *nbuf, char *opts)
cp = strchr(name, '=');
if (cp != NULL)
*cp = '\0';
- if (in_access_list(NULL, &nbuf, &hl, val)) {
+ if (in_access_list(&cln, val) > 0) {
result = name;
break;
}
@@ -162,8 +149,8 @@ charmap_search(struct netbuf *nbuf, char *opts)
if (result != NULL)
result = strdup(result);
+ cln_fini(&cln);
free(copts);
- freenetconfigent(nconf);
return (result);
}
diff --git a/usr/src/cmd/fs.d/nfs/mountd/nfsauth.c b/usr/src/cmd/fs.d/nfs/mountd/nfsauth.c
index 34a971759b..fe49f911b2 100644
--- a/usr/src/cmd/fs.d/nfs/mountd/nfsauth.c
+++ b/usr/src/cmd/fs.d/nfs/mountd/nfsauth.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -57,69 +57,31 @@
static void
nfsauth_access(auth_req *argp, auth_res *result)
{
- struct netconfig *nconf;
- struct nd_hostservlist *clnames = NULL;
struct netbuf nbuf;
struct share *sh;
- char tmp[MAXIPADDRLEN];
- char *host = NULL;
- result->auth_perm = NFSAUTH_DENIED;
+ struct cln cln;
- /*
- * Convert the client's address to a hostname
- */
- nconf = getnetconfigent(argp->req_netid);
- if (nconf == NULL) {
- syslog(LOG_ERR, "No netconfig entry for %s", argp->req_netid);
- return;
- }
+ result->auth_perm = NFSAUTH_DENIED;
nbuf.len = argp->req_client.n_len;
nbuf.buf = argp->req_client.n_bytes;
if (nbuf.len == 0 || nbuf.buf == NULL)
- goto done;
-
- if (netdir_getbyaddr(nconf, &clnames, &nbuf)) {
- host = &tmp[0];
- if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
- struct sockaddr_in *sa;
-
- /* LINTED pointer alignment */
- sa = (struct sockaddr_in *)nbuf.buf;
- (void) inet_ntoa_r(sa->sin_addr, tmp);
- } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
- struct sockaddr_in6 *sa;
- /* LINTED pointer */
- sa = (struct sockaddr_in6 *)nbuf.buf;
- (void) inet_ntop(AF_INET6, sa->sin6_addr.s6_addr,
- tmp, INET6_ADDRSTRLEN);
- }
- clnames = anon_client(host);
- }
- /*
- * Both netdir_getbyaddr() and anon_client() can return a NULL
- * clnames. This has been seen when the DNS entry for the client
- * name does not have the correct format or a reverse lookup DNS
- * entry cannot be found for the client's IP address.
- */
- if (clnames == NULL) {
- syslog(LOG_ERR, "Could not find DNS entry for %s",
- argp->req_netid);
- goto done;
- }
+ return;
/*
- * Now find the export
+ * Find the export
*/
sh = findentry(argp->req_path);
if (sh == NULL) {
syslog(LOG_ERR, "%s not exported", argp->req_path);
- goto done;
+ return;
}
- result->auth_perm = check_client(sh, &nbuf, clnames, argp->req_flavor,
+ cln_init_lazy(&cln, argp->req_netid, &nbuf);
+
+ result->auth_perm = check_client(sh, &cln, argp->req_flavor,
argp->req_clnt_uid, argp->req_clnt_gid, argp->req_clnt_gids.len,
argp->req_clnt_gids.val, &result->auth_srv_uid,
&result->auth_srv_gid, &result->auth_srv_gids.len,
@@ -128,14 +90,13 @@ nfsauth_access(auth_req *argp, auth_res *result)
sharefree(sh);
if (result->auth_perm == NFSAUTH_DENIED) {
- syslog(LOG_ERR, "%s denied access to %s",
- clnames->h_hostservs[0].h_host, argp->req_path);
+ char *host = cln_gethost(&cln);
+ if (host != NULL)
+ syslog(LOG_ERR, "%s denied access to %s", host,
+ argp->req_path);
}
-done:
- freenetconfigent(nconf);
- if (clnames)
- netdir_free(clnames, ND_HOSTSERVLIST);
+ cln_fini(&cln);
}
void