* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $Id$
*/
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
-#define NFS_NGROUPS 16
-
-#define GSS_CRED_SLACK 1024 /* XXX: unused */
+#define GSS_CRED_SLACK 1024
/* length of a krb5 verifier (48), plus data added before arguments when
* using integrity (two 4-byte integers): */
#define GSS_VERF_SLACK 100
-/* XXX this define must match the gssd define
-* as it is passed to gssd to signal the use of
-* machine creds should be part of the shared rpc interface */
-
-#define CA_RUN_AS_MACHINE 0x00000200
-
-/* dump the buffer in `emacs-hexl' style */
-#define isprint(c) ((c > 0x1f) && (c < 0x7f))
-
struct gss_auth {
struct kref kref;
struct rpc_auth rpc_auth;
gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
{
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
- struct gss_cl_ctx *old;
- old = gss_cred->gc_ctx;
+ if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
+ return;
+ gss_get_ctx(ctx);
rcu_assign_pointer(gss_cred->gc_ctx, ctx);
set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
+ smp_mb__before_clear_bit();
clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
- if (old)
- gss_put_ctx(old);
-}
-
-static int
-gss_cred_is_uptodate_ctx(struct rpc_cred *cred)
-{
- struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
- int res = 0;
-
- rcu_read_lock();
- if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx)
- res = 1;
- rcu_read_unlock();
- return res;
}
static const void *
q = (const void *)((const char *)p + len);
if (unlikely(q > end || q < p))
return ERR_PTR(-EFAULT);
- dest->data = kmemdup(p, len, GFP_KERNEL);
+ dest->data = kmemdup(p, len, GFP_NOFS);
if (unlikely(dest->data == NULL))
return ERR_PTR(-ENOMEM);
dest->len = len;
{
struct gss_cl_ctx *ctx;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc(sizeof(*ctx), GFP_NOFS);
if (ctx != NULL) {
ctx->gc_proc = RPC_GSS_PROC_DATA;
ctx->gc_seq = 1; /* NetApp 6.4R1 doesn't accept seq. no. 0 */
BUG_ON(!list_empty(&gss_msg->list));
if (gss_msg->ctx != NULL)
gss_put_ctx(gss_msg->ctx);
+ rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
kfree(gss_msg);
}
return NULL;
}
-/* Try to add a upcall to the pipefs queue.
+/* Try to add an upcall to the pipefs queue.
* If an upcall owned by our uid already exists, then we return a reference
* to that upcall instead of adding the new upcall.
*/
spin_lock(&inode->i_lock);
if (gss_msg->ctx)
- gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx));
+ gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
else
task->tk_status = gss_msg->msg.errno;
gss_cred->gc_upcall = NULL;
{
struct gss_upcall_msg *gss_msg;
- gss_msg = kzalloc(sizeof(*gss_msg), GFP_KERNEL);
+ gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
if (gss_msg != NULL) {
INIT_LIST_HEAD(&gss_msg->list);
rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
static struct gss_upcall_msg *
gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred)
{
+ struct gss_cred *gss_cred = container_of(cred,
+ struct gss_cred, gc_base);
struct gss_upcall_msg *gss_new, *gss_msg;
+ uid_t uid = cred->cr_uid;
- gss_new = gss_alloc_msg(gss_auth, cred->cr_uid);
+ /* Special case: rpc.gssd assumes that uid == 0 implies machine creds */
+ if (gss_cred->gc_machine_cred != 0)
+ uid = 0;
+
+ gss_new = gss_alloc_msg(gss_auth, uid);
if (gss_new == NULL)
return ERR_PTR(-ENOMEM);
gss_msg = gss_add_msg(gss_auth, gss_new);
}
spin_lock(&inode->i_lock);
if (gss_cred->gc_upcall != NULL)
- rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL);
- else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
+ rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
+ else if (gss_msg->ctx != NULL) {
+ gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
+ gss_cred->gc_upcall = NULL;
+ rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
+ } else if (gss_msg->msg.errno >= 0) {
task->tk_timeout = 0;
gss_cred->gc_upcall = gss_msg;
/* gss_upcall_callback will release the reference to gss_upcall_msg */
atomic_inc(&gss_msg->count);
- rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL);
+ rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback);
} else
err = gss_msg->msg.errno;
spin_unlock(&inode->i_lock);
schedule();
}
if (gss_msg->ctx)
- gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx));
+ gss_cred_set_ctx(cred, gss_msg->ctx);
else
err = gss_msg->msg.errno;
spin_unlock(&inode->i_lock);
{
const void *p, *end;
void *buf;
- struct rpc_clnt *clnt;
struct gss_upcall_msg *gss_msg;
struct inode *inode = filp->f_path.dentry->d_inode;
struct gss_cl_ctx *ctx;
if (mlen > MSG_BUF_MAXSIZE)
goto out;
err = -ENOMEM;
- buf = kmalloc(mlen, GFP_KERNEL);
+ buf = kmalloc(mlen, GFP_NOFS);
if (!buf)
goto out;
- clnt = RPC_I(inode)->private;
err = -EFAULT;
if (copy_from_user(buf, src, mlen))
goto err;
struct rpc_task *task;
if (gss_cred->gc_ctx == NULL ||
- gss_cred->gc_ctx->gc_proc == RPC_GSS_PROC_DESTROY)
+ test_and_clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
return 0;
gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY;
* by the RPC call or by the put_rpccred() below */
get_rpccred(cred);
- task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC);
+ task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC|RPC_TASK_SOFT);
if (!IS_ERR(task))
rpc_put_task(task);
dprintk("RPC: gss_create_cred for uid %d, flavor %d\n",
acred->uid, auth->au_flavor);
- if (!(cred = kzalloc(sizeof(*cred), GFP_KERNEL)))
+ if (!(cred = kzalloc(sizeof(*cred), GFP_NOFS)))
goto out_err;
rpcauth_init_cred(&cred->gc_base, acred, auth, &gss_credops);
*/
cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW;
cred->gc_service = gss_auth->service;
+ cred->gc_machine_cred = acred->machine_cred;
kref_get(&gss_auth->kref);
return &cred->gc_base;
{
struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
- /*
- * If the searchflags have set RPCAUTH_LOOKUP_NEW, then
- * we don't really care if the credential has expired or not,
- * since the caller should be prepared to reinitialise it.
- */
- if ((flags & RPCAUTH_LOOKUP_NEW) && test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
+ if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
goto out;
/* Don't match with creds that have expired. */
- if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
+ if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
+ return 0;
+ if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags))
return 0;
out:
+ if (acred->machine_cred != gss_cred->gc_machine_cred)
+ return 0;
return (rc->cr_uid == acred->uid);
}
return NULL;
}
+static int gss_renew_cred(struct rpc_task *task)
+{
+ struct rpc_cred *oldcred = task->tk_msg.rpc_cred;
+ struct gss_cred *gss_cred = container_of(oldcred,
+ struct gss_cred,
+ gc_base);
+ struct rpc_auth *auth = oldcred->cr_auth;
+ struct auth_cred acred = {
+ .uid = oldcred->cr_uid,
+ .machine_cred = gss_cred->gc_machine_cred,
+ };
+ struct rpc_cred *new;
+
+ new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW);
+ if (IS_ERR(new))
+ return PTR_ERR(new);
+ task->tk_msg.rpc_cred = new;
+ put_rpccred(oldcred);
+ return 0;
+}
+
/*
* Refresh credentials. XXX - finish
*/
static int
gss_refresh(struct rpc_task *task)
{
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ int ret = 0;
+
+ if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
+ !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) {
+ ret = gss_renew_cred(task);
+ if (ret < 0)
+ goto out;
+ cred = task->tk_msg.rpc_cred;
+ }
- if (!gss_cred_is_uptodate_ctx(task->tk_msg.rpc_cred))
- return gss_refresh_upcall(task);
- return 0;
+ if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
+ ret = gss_refresh_upcall(task);
+out:
+ return ret;
}
/* Dummy refresh routine: used only when destroying the context */
static const struct rpc_authops authgss_ops = {
.owner = THIS_MODULE,
.au_flavor = RPC_AUTH_GSS,
-#ifdef RPC_DEBUG
.au_name = "RPCSEC_GSS",
-#endif
.create = gss_create,
.destroy = gss_destroy,
.lookup_cred = gss_lookup_cred,
.cr_name = "AUTH_GSS",
.crdestroy = gss_destroy_cred,
.cr_init = gss_cred_init,
+ .crbind = rpcauth_generic_bind_cred,
.crmatch = gss_match,
.crmarshal = gss_marshal,
.crrefresh = gss_refresh,
static const struct rpc_credops gss_nullops = {
.cr_name = "AUTH_GSS",
.crdestroy = gss_destroy_cred,
+ .crbind = rpcauth_generic_bind_cred,
.crmatch = gss_match,
.crmarshal = gss_marshal,
.crrefresh = gss_refresh_null,