diff options
author | Marcel Telka <marcel.telka@nexenta.com> | 2015-10-15 09:00:58 +0200 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2015-11-02 17:56:05 -0800 |
commit | a9685eaab1313767d1d4dac672c3a468519aa899 (patch) | |
tree | 95722bb8a0406610d6856901bb98710a9787c80e /usr/src | |
parent | 33e8313d921ed710d7c5957cea98e220a663a1d5 (diff) | |
download | illumos-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.c | 580 | ||||
-rw-r--r-- | usr/src/cmd/fs.d/nfs/mountd/mountd.h | 31 | ||||
-rw-r--r-- | usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c | 33 | ||||
-rw-r--r-- | usr/src/cmd/fs.d/nfs/mountd/nfsauth.c | 67 |
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 |