diff options
author | Keith M Wesolowski <wesolows@foobazco.org> | 2014-11-26 15:46:58 +0000 |
---|---|---|
committer | Keith M Wesolowski <wesolows@foobazco.org> | 2014-11-26 15:46:58 +0000 |
commit | 77bc8c31dfc660f8542afa8a1ecc55f05486e75a (patch) | |
tree | 26a56ae42f3e27681488fade1f57fd0e7205355d /usr/src/uts/common | |
parent | 3eb4dd4330b21c3bee973f4b117529f86d8794e0 (diff) | |
parent | 0cc80ade12a7ed4a67d90f6496ecf40c87e8ff16 (diff) | |
download | illumos-joyent-77bc8c31dfc660f8542afa8a1ecc55f05486e75a.tar.gz |
[illumos-gate merge]
commit 0cc80ade12a7ed4a67d90f6496ecf40c87e8ff16
5335 psrset should support specifying a zone to bind
commit 89621fe174cf95ae903df6ceab605bf24d696ac3
5296 Support for more than 16 groups with AUTH_SYS
commit 64e4e50ab4bc3670a29e5691e3dd935c94f0a5d7
5341 gcore fails with "no such file or directory" if write fails ... error is misleading
Conflicts:
usr/src/cmd/mdb/common/modules/genunix/gcore.c
usr/src/cmd/mdb/common/mdb/mdb_err.c
usr/src/cmd/fs.d/nfs/mountd/mountd.c
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r-- | usr/src/uts/common/conf/param.c | 6 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs_auth.c | 456 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs_auth_xdr.c | 8 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs_server.c | 23 | ||||
-rw-r--r-- | usr/src/uts/common/nfs/auth.h | 26 | ||||
-rw-r--r-- | usr/src/uts/common/nfs/export.h | 13 | ||||
-rw-r--r-- | usr/src/uts/common/nfs/nfs.h | 5 | ||||
-rw-r--r-- | usr/src/uts/common/sys/param.h | 3 |
8 files changed, 355 insertions, 185 deletions
diff --git a/usr/src/uts/common/conf/param.c b/usr/src/uts/common/conf/param.c index 7a7b9a208b..a71be771fd 100644 --- a/usr/src/uts/common/conf/param.c +++ b/usr/src/uts/common/conf/param.c @@ -18,7 +18,9 @@ * * CDDL HEADER END */ + /* + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 1983, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright 2012 Milan Jurik. All rights reserved. @@ -594,10 +596,6 @@ param_calc(int platform_max_nprocs) cmn_err(CE_NOTE, "maxusers limited to %d", MAX_MAXUSERS); } - if (ngroups_max > NGROUPS_MAX_DEFAULT) - cmn_err(CE_WARN, "ngroups_max of %d > %d, NFS AUTH_SYS will" - " not work properly", ngroups_max, NGROUPS_MAX_DEFAULT); - #ifdef DEBUG /* * The purpose of maxusers is to prevent memory overcommit. diff --git a/usr/src/uts/common/fs/nfs/nfs_auth.c b/usr/src/uts/common/fs/nfs/nfs_auth.c index d20780ebba..18d358795b 100644 --- a/usr/src/uts/common/fs/nfs/nfs_auth.c +++ b/usr/src/uts/common/fs/nfs/nfs_auth.c @@ -18,9 +18,10 @@ * * CDDL HEADER END */ + /* - * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/param.h> @@ -177,7 +178,7 @@ void mountd_args(uint_t did) { mutex_enter(&mountd_lock); - if (mountd_dh) + if (mountd_dh != NULL) door_ki_rele(mountd_dh); mountd_dh = door_ki_lookup(did); mutex_exit(&mountd_lock); @@ -317,11 +318,11 @@ addrmask(struct netbuf *addr, struct netbuf *mask) */ int nfsauth4_access(struct exportinfo *exi, vnode_t *vp, struct svc_req *req, - cred_t *cr, uid_t *uid, gid_t *gid) + cred_t *cr, uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids) { int access; - access = nfsauth_access(exi, req, cr, uid, gid); + access = nfsauth_access(exi, req, cr, uid, gid, ngids, gids); /* * There are cases that the server needs to allow the client @@ -370,17 +371,14 @@ sys_log(const char *msg) static bool_t nfsauth_retrieve(struct exportinfo *exi, char *req_netid, int flavor, struct netbuf *addr, int *access, uid_t clnt_uid, gid_t clnt_gid, - uid_t *srv_uid, gid_t *srv_gid) + uint_t clnt_gids_cnt, const gid_t *clnt_gids, uid_t *srv_uid, + gid_t *srv_gid, uint_t *srv_gids_cnt, gid_t **srv_gids) { varg_t varg = {0}; nfsauth_res_t res = {0}; - XDR xdrs_a; - XDR xdrs_r; + XDR xdrs; size_t absz; caddr_t abuf; - size_t rbsz = (size_t)(BYTES_PER_XDR_UNIT * 4); - char result[BYTES_PER_XDR_UNIT * 4] = {0}; - caddr_t rbuf = (caddr_t)&result; int last = 0; door_arg_t da; door_info_t di; @@ -392,35 +390,7 @@ nfsauth_retrieve(struct exportinfo *exi, char *req_netid, int flavor, * so we need to call the nfsauth service in the * mount daemon. */ -retry: - mutex_enter(&mountd_lock); - dh = mountd_dh; - if (dh) - door_ki_hold(dh); - mutex_exit(&mountd_lock); - - if (dh == NULL) { - /* - * The rendezvous point has not been established yet ! - * This could mean that either mountd(1m) has not yet - * been started or that _this_ routine nuked the door - * handle after receiving an EINTR for a REVOKED door. - * - * Returning NFSAUTH_DROP will cause the NFS client - * to retransmit the request, so let's try to be more - * rescillient and attempt for ntries before we bail. - */ - if (++ntries % NFSAUTH_DR_TRYCNT) { - delay(hz); - goto retry; - } - - sys_log("nfsauth: mountd has not established door"); - *access = NFSAUTH_DROP; - return (FALSE); - } - ntries = 0; varg.vers = V_PROTO; varg.arg_u.arg.cmd = NFSAUTH_ACCESS; varg.arg_u.arg.areq.req_client.n_len = addr->len; @@ -430,6 +400,10 @@ retry: varg.arg_u.arg.areq.req_flavor = flavor; varg.arg_u.arg.areq.req_clnt_uid = clnt_uid; varg.arg_u.arg.areq.req_clnt_gid = clnt_gid; + varg.arg_u.arg.areq.req_clnt_gids.len = clnt_gids_cnt; + varg.arg_u.arg.areq.req_clnt_gids.val = (gid_t *)clnt_gids; + + DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg); /* * Setup the XDR stream for encoding the arguments. Notice that @@ -440,153 +414,175 @@ retry: * info _or_ properly encode the arguments, there's really no * point in continuting, so we fail the request. */ - DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg); - if ((absz = xdr_sizeof(xdr_varg, (void *)&varg)) == 0) { - door_ki_rele(dh); + if ((absz = xdr_sizeof(xdr_varg, &varg)) == 0) { *access = NFSAUTH_DENIED; return (FALSE); } abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP); - xdrmem_create(&xdrs_a, abuf, absz, XDR_ENCODE); - if (!xdr_varg(&xdrs_a, &varg)) { - door_ki_rele(dh); + xdrmem_create(&xdrs, abuf, absz, XDR_ENCODE); + if (!xdr_varg(&xdrs, &varg)) { + XDR_DESTROY(&xdrs); goto fail; } - XDR_DESTROY(&xdrs_a); + XDR_DESTROY(&xdrs); /* - * The result (nfsauth_res_t) is always four int's, so we don't - * have to dynamically size (or allocate) the results buffer. - * Now that we've got what we need, we prep the door arguments - * and place the call. + * Prepare the door arguments + * + * We don't know the size of the message the daemon + * will pass back to us. By setting rbuf to NULL, + * we force the door code to allocate a buf of the + * appropriate size. We must set rsize > 0, however, + * else the door code acts as if no response was + * expected and doesn't pass the data to us. */ da.data_ptr = (char *)abuf; da.data_size = absz; da.desc_ptr = NULL; da.desc_num = 0; - da.rbuf = (char *)rbuf; - da.rsize = rbsz; + da.rbuf = NULL; + da.rsize = 1; - switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) { - case 0: /* Success */ - if (da.data_ptr != da.rbuf && da.data_size == 0) { - /* - * The door_return that contained the data - * failed ! We're here because of the 2nd - * door_return (w/o data) such that we can - * get control of the thread (and exit - * gracefully). - */ - DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil, - door_arg_t *, &da); - door_ki_rele(dh); - goto fail; +retry: + mutex_enter(&mountd_lock); + dh = mountd_dh; + if (dh != NULL) + door_ki_hold(dh); + mutex_exit(&mountd_lock); - } else if (rbuf != da.rbuf) { - /* - * The only time this should be true - * is iff userland wanted to hand us - * a bigger response than what we - * expect; that should not happen - * (nfsauth_res_t is only 4 int's), - * but we check nevertheless. - */ - rbuf = da.rbuf; - rbsz = da.rsize; + if (dh == NULL) { + /* + * The rendezvous point has not been established yet! + * This could mean that either mountd(1m) has not yet + * been started or that _this_ routine nuked the door + * handle after receiving an EINTR for a REVOKED door. + * + * Returning NFSAUTH_DROP will cause the NFS client + * to retransmit the request, so let's try to be more + * rescillient and attempt for ntries before we bail. + */ + if (++ntries % NFSAUTH_DR_TRYCNT) { + delay(hz); + goto retry; + } - } else if (rbsz > da.data_size) { - /* - * We were expecting four int's; but if - * userland fails in encoding the XDR - * stream, we detect that here, since - * the mountd forces down only one byte - * in such scenario. - */ - door_ki_rele(dh); - goto fail; - } - door_ki_rele(dh); - break; + kmem_free(abuf, absz); + + sys_log("nfsauth: mountd has not established door"); + *access = NFSAUTH_DROP; + return (FALSE); + } + + ntries = 0; + + /* + * Now that we've got what we need, place the call. + */ + switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) { + case 0: /* Success */ + door_ki_rele(dh); - case EAGAIN: + if (da.data_ptr == NULL && da.data_size == 0) { /* - * Server out of resources; back off for a bit + * The door_return that contained the data + * failed! We're here because of the 2nd + * door_return (w/o data) such that we can + * get control of the thread (and exit + * gracefully). */ + DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil, + door_arg_t *, &da); + goto fail; + } + + break; + + case EAGAIN: + /* + * Server out of resources; back off for a bit + */ + door_ki_rele(dh); + delay(hz); + goto retry; + /* NOTREACHED */ + + case EINTR: + if (!door_ki_info(dh, &di)) { door_ki_rele(dh); - kmem_free(abuf, absz); - delay(hz); - goto retry; - /* NOTREACHED */ - case EINTR: - if (!door_ki_info(dh, &di)) { - if (di.di_attributes & DOOR_REVOKED) { - /* - * The server barfed and revoked - * the (existing) door on us; we - * want to wait to give smf(5) a - * chance to restart mountd(1m) - * and establish a new door handle. - */ - mutex_enter(&mountd_lock); - if (dh == mountd_dh) - mountd_dh = NULL; - mutex_exit(&mountd_lock); - door_ki_rele(dh); - kmem_free(abuf, absz); - delay(hz); - goto retry; - } + if (di.di_attributes & DOOR_REVOKED) { /* - * If the door was _not_ revoked on us, - * then more than likely we took an INTR, - * so we need to fail the operation. + * The server barfed and revoked + * the (existing) door on us; we + * want to wait to give smf(5) a + * chance to restart mountd(1m) + * and establish a new door handle. */ - door_ki_rele(dh); - goto fail; - } - /* - * The only failure that can occur from getting - * the door info is EINVAL, so we let the code - * below handle it. - */ - /* FALLTHROUGH */ - - case EBADF: - case EINVAL: - default: - /* - * If we have a stale door handle, give smf a last - * chance to start it by sleeping for a little bit. - * If we're still hosed, we'll fail the call. - * - * Since we're going to reacquire the door handle - * upon the retry, we opt to sleep for a bit and - * _not_ to clear mountd_dh. If mountd restarted - * and was able to set mountd_dh, we should see - * the new instance; if not, we won't get caught - * up in the retry/DELAY loop. - */ - door_ki_rele(dh); - if (!last) { + mutex_enter(&mountd_lock); + if (dh == mountd_dh) { + door_ki_rele(mountd_dh); + mountd_dh = NULL; + } + mutex_exit(&mountd_lock); delay(hz); - last++; goto retry; } - sys_log("nfsauth: stale mountd door handle"); + /* + * If the door was _not_ revoked on us, + * then more than likely we took an INTR, + * so we need to fail the operation. + */ goto fail; + } + /* + * The only failure that can occur from getting + * the door info is EINVAL, so we let the code + * below handle it. + */ + /* FALLTHROUGH */ + + case EBADF: + case EINVAL: + default: + /* + * If we have a stale door handle, give smf a last + * chance to start it by sleeping for a little bit. + * If we're still hosed, we'll fail the call. + * + * Since we're going to reacquire the door handle + * upon the retry, we opt to sleep for a bit and + * _not_ to clear mountd_dh. If mountd restarted + * and was able to set mountd_dh, we should see + * the new instance; if not, we won't get caught + * up in the retry/DELAY loop. + */ + door_ki_rele(dh); + if (!last) { + delay(hz); + last++; + goto retry; + } + sys_log("nfsauth: stale mountd door handle"); + goto fail; } + ASSERT(da.rbuf != NULL); + /* * No door errors encountered; setup the XDR stream for decoding * the results. If we fail to decode the results, we've got no * other recourse than to fail the request. */ - xdrmem_create(&xdrs_r, rbuf, rbsz, XDR_DECODE); - if (!xdr_nfsauth_res(&xdrs_r, &res)) + xdrmem_create(&xdrs, da.rbuf, da.rsize, XDR_DECODE); + if (!xdr_nfsauth_res(&xdrs, &res)) { + xdr_free(xdr_nfsauth_res, (char *)&res); + XDR_DESTROY(&xdrs); + kmem_free(da.rbuf, da.rsize); goto fail; - XDR_DESTROY(&xdrs_r); + } + XDR_DESTROY(&xdrs); + kmem_free(da.rbuf, da.rsize); DTRACE_PROBE1(nfsserv__func__nfsauth__results, nfsauth_res_t *, &res); switch (res.stat) { @@ -594,13 +590,18 @@ retry: *access = res.ares.auth_perm; *srv_uid = res.ares.auth_srv_uid; *srv_gid = res.ares.auth_srv_gid; - kmem_free(abuf, absz); + *srv_gids_cnt = res.ares.auth_srv_gids.len; + *srv_gids = kmem_alloc(*srv_gids_cnt * sizeof (gid_t), + KM_SLEEP); + bcopy(res.ares.auth_srv_gids.val, *srv_gids, + *srv_gids_cnt * sizeof (gid_t)); break; case NFSAUTH_DR_EFAIL: case NFSAUTH_DR_DECERR: case NFSAUTH_DR_BADCMD: default: + xdr_free(xdr_nfsauth_res, (char *)&res); fail: *access = NFSAUTH_DENIED; kmem_free(abuf, absz); @@ -608,6 +609,9 @@ fail: /* NOTREACHED */ } + xdr_free(xdr_nfsauth_res, (char *)&res); + kmem_free(abuf, absz); + return (TRUE); } @@ -655,6 +659,8 @@ nfsauth_refresh_thread(void) */ while ((ran = list_remove_head(&ren->ren_authlist))) { + uint_t ngids; + gid_t *gids; struct auth_cache *p = ran->ran_auth; ASSERT(p != NULL); @@ -715,7 +721,8 @@ nfsauth_refresh_thread(void) retrieval = nfsauth_retrieve(exi, p->auth_netid, p->auth_flavor, &p->auth_addr, &access, p->auth_clnt_uid, p->auth_clnt_gid, - &p->auth_srv_uid, &p->auth_srv_gid); + p->auth_clnt_ngids, p->auth_clnt_gids, + &p->auth_srv_uid, &p->auth_srv_gid, &ngids, &gids); /* * This can only be set in one other place @@ -728,6 +735,8 @@ nfsauth_refresh_thread(void) if (p->auth_state == NFS_AUTH_INVALID) { mutex_exit(&p->auth_lock); nfsauth_remove_dead_entry(p); + if (retrieval == TRUE) + kmem_free(gids, ngids * sizeof (gid_t)); } else { /* * If we got an error, do not reset the @@ -737,6 +746,12 @@ nfsauth_refresh_thread(void) */ if (retrieval == TRUE) { p->auth_access = access; + + kmem_free(p->auth_srv_gids, + p->auth_srv_ngids * sizeof (gid_t)); + p->auth_srv_ngids = ngids; + p->auth_srv_gids = gids; + p->auth_freshness = gethrestime_sec(); } p->auth_state = NFS_AUTH_FRESH; @@ -761,13 +776,14 @@ nfsauth_refresh_thread(void) */ static int nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor, - cred_t *cr, uid_t *uid, gid_t *gid) + cred_t *cr, uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids) { struct netbuf *taddrmask; struct netbuf addr; struct netbuf *claddr; struct auth_cache **head; struct auth_cache *p; + struct auth_cache *prev = NULL; int access; time_t refresh; @@ -776,6 +792,8 @@ nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor, uid_t tmpuid; gid_t tmpgid; + uint_t tmpngids; + gid_t *tmpgids; ASSERT(cr != NULL); @@ -805,9 +823,53 @@ nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor, crgetuid(cr) == p->auth_clnt_uid && crgetgid(cr) == p->auth_clnt_gid) break; + prev = p; } if (p != NULL) { + /* + * In a case the client's supplemental groups changed we need + * to discard the auth_cache entry and re-retrieve it. + */ + mutex_enter(&p->auth_lock); + if (p->auth_clnt_ngids != crgetngroups(cr) || + bcmp(p->auth_clnt_gids, crgetgroups(cr), + p->auth_clnt_ngids * sizeof (gid_t))) { + auth_state_t prev_state = p->auth_state; + + p->auth_state = NFS_AUTH_INVALID; + mutex_exit(&p->auth_lock); + + if (prev_state == NFS_AUTH_FRESH) { + if (rw_tryupgrade(&exi->exi_cache_lock) == 0) { + struct auth_cache *tmp; + + rw_exit(&exi->exi_cache_lock); + rw_enter(&exi->exi_cache_lock, + RW_WRITER); + + prev = NULL; + for (tmp = *head; tmp != NULL; + tmp = tmp->auth_next) { + if (p == tmp) + break; + prev = p; + } + } + + if (prev == NULL) + exi->exi_cache[hash(&addr)] = + p->auth_next; + else + prev->auth_next = p->auth_next; + + nfsauth_free_node(p); + } + + goto retrieve; + } + mutex_exit(&p->auth_lock); + nfsauth_cache_hit++; refresh = gethrestime_sec() - p->auth_freshness; @@ -889,6 +951,11 @@ nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor, *uid = p->auth_srv_uid; if (gid != NULL) *gid = p->auth_srv_gid; + if (ngids != NULL && gids != NULL) { + *ngids = p->auth_srv_ngids; + *gids = kmem_alloc(*ngids * sizeof (gid_t), KM_SLEEP); + bcopy(p->auth_srv_gids, *gids, *ngids * sizeof (gid_t)); + } p->auth_time = gethrestime_sec(); @@ -898,13 +965,19 @@ nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor, return (access); } +retrieve: rw_exit(&exi->exi_cache_lock); nfsauth_cache_miss++; if (!nfsauth_retrieve(exi, svc_getnetid(req->rq_xprt), flavor, - &addr, &access, crgetuid(cr), crgetgid(cr), &tmpuid, &tmpgid)) { + &addr, &access, crgetuid(cr), crgetgid(cr), crgetngroups(cr), + crgetgroups(cr), &tmpuid, &tmpgid, &tmpngids, &tmpgids)) { kmem_free(addr.buf, addr.len); + if (ngids != NULL && gids != NULL) { + *ngids = 0; + *gids = NULL; + } return (access); } @@ -912,19 +985,39 @@ nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor, *uid = tmpuid; if (gid != NULL) *gid = tmpgid; + if (ngids != NULL && gids != NULL) { + *ngids = tmpngids; + *gids = tmpgids; + + /* + * We need a copy of gids for the auth_cache entry + */ + tmpgids = kmem_alloc(tmpngids * sizeof (gid_t), KM_NOSLEEP); + if (tmpgids != NULL) + bcopy(*gids, tmpgids, tmpngids * sizeof (gid_t)); + } /* * Now cache the result on the cache chain * for this export (if there's enough memory) */ p = kmem_cache_alloc(exi_cache_handle, KM_NOSLEEP); - if (p != NULL) { + if (p != NULL) + p->auth_clnt_gids = kmem_alloc( + crgetngroups(cr) * sizeof (gid_t), KM_NOSLEEP); + if (p != NULL && (tmpngids == 0 || tmpgids != NULL) && + (crgetngroups(cr) == 0 || p->auth_clnt_gids != NULL)) { p->auth_addr = addr; p->auth_flavor = flavor; p->auth_clnt_uid = crgetuid(cr); p->auth_clnt_gid = crgetgid(cr); + p->auth_clnt_ngids = crgetngroups(cr); + bcopy(crgetgroups(cr), p->auth_clnt_gids, + p->auth_clnt_ngids * sizeof (gid_t)); p->auth_srv_uid = tmpuid; p->auth_srv_gid = tmpgid; + p->auth_srv_ngids = tmpngids; + p->auth_srv_gids = tmpgids; p->auth_access = access; p->auth_time = p->auth_freshness = gethrestime_sec(); p->auth_state = NFS_AUTH_FRESH; @@ -937,6 +1030,14 @@ nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor, rw_exit(&exi->exi_cache_lock); } else { kmem_free(addr.buf, addr.len); + if (tmpgids != NULL) + kmem_free(tmpgids, tmpngids * sizeof (gid_t)); + if (p != NULL) { + if (p->auth_clnt_gids != NULL) + kmem_free(p->auth_clnt_gids, + crgetngroups(cr) * sizeof (gid_t)); + kmem_cache_free(exi_cache_handle, p); + } } return (access); @@ -967,14 +1068,15 @@ nfsauth4_secinfo_access(struct exportinfo *exi, struct svc_req *req, return (NFSAUTH_RW); } - access = nfsauth_cache_get(exi, req, flavor, cr, NULL, NULL); + access = nfsauth_cache_get(exi, req, flavor, cr, NULL, NULL, NULL, + NULL); return (access); } int nfsauth_access(struct exportinfo *exi, struct svc_req *req, cred_t *cr, - uid_t *uid, gid_t *gid) + uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids) { int access, mapaccess; struct secinfo *sp; @@ -1021,17 +1123,22 @@ nfsauth_access(struct exportinfo *exi, struct svc_req *req, cred_t *cr, * This might get overriden later in nfsauth_cache_get(). */ if (crgetuid(cr) == 0) { - if (uid) + if (uid != NULL) *uid = exi->exi_export.ex_anon; - if (gid) + if (gid != NULL) *gid = exi->exi_export.ex_anon; } else { - if (uid) + if (uid != NULL) *uid = crgetuid(cr); - if (gid) + if (gid != NULL) *gid = crgetgid(cr); } + if (ngids != NULL) + *ngids = 0; + if (gids != NULL) + *gids = NULL; + /* * If the flavor is in the ex_secinfo list, but not an explicitly * shared flavor by the user, it is a result of the nfsv4 server @@ -1054,10 +1161,12 @@ nfsauth_access(struct exportinfo *exi, struct svc_req *req, cred_t *cr, return (mapaccess | NFSAUTH_RO); /* - * Optimize if there are no lists + * Optimize if there are no lists. + * We cannot optimize for AUTH_SYS with NGRPS (16) supplemental groups. */ perm = sp[i].s_flags; - if ((perm & (M_ROOT | M_NONE | M_MAP)) == 0) { + if ((perm & (M_ROOT | M_NONE | M_MAP)) == 0 && (ngroups_max <= NGRPS || + flavor != AUTH_SYS || crgetngroups(cr) < NGRPS)) { perm &= ~M_4SEC_EXPORTED; if (perm == M_RO) return (mapaccess | NFSAUTH_RO); @@ -1065,7 +1174,19 @@ nfsauth_access(struct exportinfo *exi, struct svc_req *req, cred_t *cr, return (mapaccess | NFSAUTH_RW); } - access = nfsauth_cache_get(exi, req, flavor, cr, uid, gid); + access = nfsauth_cache_get(exi, req, flavor, cr, uid, gid, ngids, gids); + + /* + * For both NFSAUTH_DENIED and NFSAUTH_WRONGSEC we do not care about + * the supplemental groups. + */ + if (access & NFSAUTH_DENIED || access & NFSAUTH_WRONGSEC) { + if (ngids != NULL && gids != NULL) { + kmem_free(*gids, *ngids * sizeof (gid_t)); + *ngids = 0; + *gids = NULL; + } + } /* * Client's security flavor doesn't match with "ro" or @@ -1078,7 +1199,7 @@ nfsauth_access(struct exportinfo *exi, struct svc_req *req, cred_t *cr, if (authnone_entry != -1) { mapaccess = NFSAUTH_MAPNONE; access = nfsauth_cache_get(exi, req, AUTH_NONE, cr, - NULL, NULL); + NULL, NULL, NULL, NULL); } else { /* * Check for AUTH_NONE presence. @@ -1087,7 +1208,8 @@ nfsauth_access(struct exportinfo *exi, struct svc_req *req, cred_t *cr, if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) { mapaccess = NFSAUTH_MAPNONE; access = nfsauth_cache_get(exi, req, - AUTH_NONE, cr, NULL, NULL); + AUTH_NONE, cr, NULL, NULL, NULL, + NULL); break; } } @@ -1106,8 +1228,10 @@ nfsauth_free_node(struct auth_cache *p) if (p->auth_netid != NULL) kmem_free(p->auth_netid, strlen(p->auth_netid) + 1); kmem_free(p->auth_addr.buf, p->auth_addr.len); + kmem_free(p->auth_clnt_gids, p->auth_clnt_ngids * sizeof (gid_t)); + kmem_free(p->auth_srv_gids, p->auth_srv_ngids * sizeof (gid_t)); mutex_destroy(&p->auth_lock); - kmem_cache_free(exi_cache_handle, (void *)p); + kmem_cache_free(exi_cache_handle, p); } /* diff --git a/usr/src/uts/common/fs/nfs/nfs_auth_xdr.c b/usr/src/uts/common/fs/nfs/nfs_auth_xdr.c index 8fcec0e7b7..1ccba37a21 100644 --- a/usr/src/uts/common/fs/nfs/nfs_auth_xdr.c +++ b/usr/src/uts/common/fs/nfs/nfs_auth_xdr.c @@ -70,6 +70,10 @@ xdr_nfsauth_arg(XDR *xdrs, nfsauth_arg_t *argp) return (FALSE); if (!xdr_gid_t(xdrs, &argp->areq.req_clnt_gid)) return (FALSE); + if (!xdr_array(xdrs, (caddr_t *)&argp->areq.req_clnt_gids.val, + &argp->areq.req_clnt_gids.len, NGROUPS_UMAX, (uint_t)sizeof (gid_t), + xdr_gid_t)) + return (FALSE); return (TRUE); } @@ -84,5 +88,9 @@ xdr_nfsauth_res(XDR *xdrs, nfsauth_res_t *argp) return (FALSE); if (!xdr_gid_t(xdrs, &argp->ares.auth_srv_gid)) return (FALSE); + if (!xdr_array(xdrs, (caddr_t *)&argp->ares.auth_srv_gids.val, + &argp->ares.auth_srv_gids.len, NGROUPS_UMAX, (uint_t)sizeof (gid_t), + xdr_gid_t)) + return (FALSE); return (TRUE); } diff --git a/usr/src/uts/common/fs/nfs/nfs_server.c b/usr/src/uts/common/fs/nfs/nfs_server.c index 5621d2efd9..93ccd28122 100644 --- a/usr/src/uts/common/fs/nfs/nfs_server.c +++ b/usr/src/uts/common/fs/nfs/nfs_server.c @@ -2020,6 +2020,8 @@ checkauth(struct exportinfo *exi, struct svc_req *req, cred_t *cr, int anon_ok, uid_t uid; gid_t gid; + uint_t ngids; + gid_t *gids; /* * Check for privileged port number @@ -2078,7 +2080,7 @@ checkauth(struct exportinfo *exi, struct svc_req *req, cred_t *cr, int anon_ok, /* * Check if the auth flavor is valid for this export */ - access = nfsauth_access(exi, req, cr, &uid, &gid); + access = nfsauth_access(exi, req, cr, &uid, &gid, &ngids, &gids); if (access & NFSAUTH_DROP) return (-1); /* drop the request */ @@ -2114,6 +2116,9 @@ checkauth(struct exportinfo *exi, struct svc_req *req, cred_t *cr, int anon_ok, return (0); } + if (rpcflavor != AUTH_SYS) + kmem_free(gids, ngids * sizeof (gid_t)); + switch (rpcflavor) { case AUTH_NONE: anon_res = crsetugid(cr, exi->exi_export.ex_anon, @@ -2153,8 +2158,12 @@ checkauth(struct exportinfo *exi, struct svc_req *req, cred_t *cr, int anon_ok, exi->exi_export.ex_anon, exi->exi_export.ex_anon); (void) crsetgroups(cr, 0, NULL); + } else if (access & NFSAUTH_GROUPS) { + (void) crsetgroups(cr, ngids, gids); } + kmem_free(gids, ngids * sizeof (gid_t)); + break; case AUTH_DES: @@ -2272,6 +2281,8 @@ checkauth4(struct compound_state *cs, struct svc_req *req) uid_t uid; gid_t gid; + uint_t ngids; + gid_t *gids; exi = cs->exi; cr = cs->cr; @@ -2312,7 +2323,8 @@ checkauth4(struct compound_state *cs, struct svc_req *req) * Check the access right per auth flavor on the vnode of * this export for the given request. */ - access = nfsauth4_access(cs->exi, cs->vp, req, cr, &uid, &gid); + access = nfsauth4_access(cs->exi, cs->vp, req, cr, &uid, &gid, &ngids, + &gids); if (access & NFSAUTH_WRONGSEC) return (-2); /* no access for this security flavor */ @@ -2342,6 +2354,9 @@ checkauth4(struct compound_state *cs, struct svc_req *req) * return 1 on success or 0 on failure */ + if (rpcflavor != AUTH_SYS) + kmem_free(gids, ngids * sizeof (gid_t)); + switch (rpcflavor) { case AUTH_NONE: anon_res = crsetugid(cr, exi->exi_export.ex_anon, @@ -2381,8 +2396,12 @@ checkauth4(struct compound_state *cs, struct svc_req *req) exi->exi_export.ex_anon, exi->exi_export.ex_anon); (void) crsetgroups(cr, 0, NULL); + } if (access & NFSAUTH_GROUPS) { + (void) crsetgroups(cr, ngids, gids); } + kmem_free(gids, ngids * sizeof (gid_t)); + break; default: diff --git a/usr/src/uts/common/nfs/auth.h b/usr/src/uts/common/nfs/auth.h index 365b1ff6d7..5293e3fdd1 100644 --- a/usr/src/uts/common/nfs/auth.h +++ b/usr/src/uts/common/nfs/auth.h @@ -18,12 +18,14 @@ * * CDDL HEADER END */ + /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ + /* - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _AUTH_H @@ -50,6 +52,7 @@ * int req_flavor; # auth flavor * uid_t req_clnt_uid; # client's uid * gid_t req_clnt_gid; # client's gid + * gid_t req_clnt_gids<>; # client's supplemental groups * }; * * const NFSAUTH_DENIED = 0x01; # Access denied @@ -60,6 +63,7 @@ * # try a different flavor * const NFSAUTH_UIDMAP = 0x100; # uid mapped * const NFSAUTH_GIDMAP = 0x200; # gid mapped + * const NFSAUTH_GROUPS = 0x400; # translated supplemental groups * # * # The following are not part of the protocol. * # @@ -68,9 +72,10 @@ * const NFSAUTH_LIMITED = 0x80; # Access limited to visible nodes * * struct auth_res { - * int auth_perm; - * uid_t auth_srv_uid; - * gid_t auth_srv_gid; + * int auth_perm; + * uid_t auth_srv_uid; # translated uid + * gid_t auth_srv_gid; # translated gid + * gid_t auth_srv_gids<>; # translated supplemental groups * }; * * program NFSAUTH_PROG { @@ -113,6 +118,7 @@ extern "C" { #define NFSAUTH_LIMITED 0x80 #define NFSAUTH_UIDMAP 0x100 #define NFSAUTH_GIDMAP 0x200 +#define NFSAUTH_GROUPS 0x400 struct auth_req { netobj req_client; @@ -121,6 +127,10 @@ struct auth_req { int req_flavor; uid_t req_clnt_uid; gid_t req_clnt_gid; + struct { + uint_t len; + gid_t *val; + } req_clnt_gids; }; typedef struct auth_req auth_req; @@ -128,6 +138,10 @@ struct auth_res { int auth_perm; uid_t auth_srv_uid; gid_t auth_srv_gid; + struct { + uint_t len; + gid_t *val; + } auth_srv_gids; }; typedef struct auth_res auth_res; diff --git a/usr/src/uts/common/nfs/export.h b/usr/src/uts/common/nfs/export.h index 03851c1fb8..143b98fd8e 100644 --- a/usr/src/uts/common/nfs/export.h +++ b/usr/src/uts/common/nfs/export.h @@ -18,9 +18,10 @@ * * CDDL HEADER END */ + /* - * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -256,8 +257,12 @@ struct auth_cache { int auth_flavor; uid_t auth_clnt_uid; gid_t auth_clnt_gid; + uint_t auth_clnt_ngids; + gid_t *auth_clnt_gids; uid_t auth_srv_uid; gid_t auth_srv_gid; + uint_t auth_srv_ngids; + gid_t *auth_srv_gids; int auth_access; time_t auth_time; time_t auth_freshness; @@ -542,12 +547,12 @@ typedef struct exp_visible exp_visible_t; #define rdonly4(req, cs) \ (vn_is_readonly((cs)->vp) || \ (nfsauth4_access((cs)->exi, (cs)->vp, (req), (cs)->basecr, NULL, \ - NULL) & (NFSAUTH_RO | NFSAUTH_LIMITED))) + NULL, NULL, NULL) & (NFSAUTH_RO | NFSAUTH_LIMITED))) extern int nfsauth4_access(struct exportinfo *, vnode_t *, - struct svc_req *, cred_t *, uid_t *, gid_t *); + struct svc_req *, cred_t *, uid_t *, gid_t *, uint_t *, gid_t **); extern int nfsauth4_secinfo_access(struct exportinfo *, - struct svc_req *, int, int, cred_t *); + struct svc_req *, int, int, cred_t *); extern int nfs_fhbcmp(char *, char *, int); extern int nfs_exportinit(void); extern void nfs_exportfini(void); diff --git a/usr/src/uts/common/nfs/nfs.h b/usr/src/uts/common/nfs/nfs.h index b85fe98b11..681057e708 100644 --- a/usr/src/uts/common/nfs/nfs.h +++ b/usr/src/uts/common/nfs/nfs.h @@ -18,10 +18,11 @@ * * CDDL HEADER END */ + /* + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ @@ -938,7 +939,7 @@ extern int nfslookup(vnode_t *, char *, vnode_t **, struct pathname *, int, vnode_t *, cred_t *, int); extern void sv_free(struct servinfo *); extern int nfsauth_access(struct exportinfo *, struct svc_req *, cred_t *, - uid_t *, gid_t *); + uid_t *, gid_t *, uint_t *, gid_t **); extern void nfsauth_init(void); extern void nfsauth_fini(void); extern int nfs_setopts(vnode_t *, model_t, struct nfs_args *); diff --git a/usr/src/uts/common/sys/param.h b/usr/src/uts/common/sys/param.h index 657acc869e..12bdc29079 100644 --- a/usr/src/uts/common/sys/param.h +++ b/usr/src/uts/common/sys/param.h @@ -18,7 +18,9 @@ * * CDDL HEADER END */ + /* + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -131,7 +133,6 @@ extern "C" { /* * NGROUPS_MAX_DEFAULT: *MUST* match NGROUPS_MAX value in limits.h. - * Remember that the NFS protocol must rev. before this can be increased */ #define NGROUPS_MAX_DEFAULT 16 |