Commit 58acfd93 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://nfsclient.bkbits.net/linux-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 3a33f489 8d945ef7
......@@ -106,7 +106,7 @@ nfs_idmap_new(struct nfs_server *server)
"%s/idmap", idmap->idmap_server->client->cl_pathname);
idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path,
idmap->idmap_server, &idmap_upcall_ops);
idmap->idmap_server, &idmap_upcall_ops, 0);
if (IS_ERR(idmap->idmap_dentry))
goto err_free;
......
......@@ -65,7 +65,7 @@ nfs4_get_client(void)
struct nfs4_client *clp;
if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
memset(clp, 0, sizeof(nfs4_verifier));
memset(clp, 0, sizeof(*clp));
return clp;
}
......
......@@ -127,6 +127,7 @@ u32 * rpcauth_checkverf(struct rpc_task *, u32 *);
int rpcauth_refreshcred(struct rpc_task *);
void rpcauth_invalcred(struct rpc_task *);
int rpcauth_uptodatecred(struct rpc_task *);
int rpcauth_deadcred(struct rpc_task *);
void rpcauth_init_credcache(struct rpc_auth *);
void rpcauth_free_credcache(struct rpc_auth *);
......
......@@ -39,12 +39,12 @@ u32 gss_import_sec_context(
u32 gss_get_mic(
struct gss_ctx *ctx_id,
u32 qop,
struct xdr_netobj *message_buffer,
struct xdr_netobj *message_token);
struct xdr_netobj *message,
struct xdr_netobj *mic_token);
u32 gss_verify_mic(
struct gss_ctx *ctx_id,
struct xdr_netobj *signbuf,
struct xdr_netobj *checksum,
struct xdr_netobj *message,
struct xdr_netobj *mic_token,
u32 *qstate);
u32 gss_delete_sec_context(
struct gss_ctx **ctx_id);
......@@ -95,12 +95,12 @@ struct gss_api_ops {
u32 (*gss_get_mic)(
struct gss_ctx *ctx_id,
u32 qop,
struct xdr_netobj *message_buffer,
struct xdr_netobj *message_token);
struct xdr_netobj *message,
struct xdr_netobj *mic_token);
u32 (*gss_verify_mic)(
struct gss_ctx *ctx_id,
struct xdr_netobj *signbuf,
struct xdr_netobj *checksum,
struct xdr_netobj *message,
struct xdr_netobj *mic_token,
u32 *qstate);
void (*gss_delete_sec_context)(
void *internal_ctx_id);
......
......@@ -24,6 +24,8 @@ struct rpc_inode {
int pipelen;
int nreaders;
wait_queue_head_t waitq;
#define RPC_PIPE_WAIT_FOR_OPEN 1
int flags;
struct rpc_pipe_ops *ops;
};
......@@ -38,10 +40,11 @@ extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
extern int rpc_rmdir(char *);
extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *);
extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags);
extern int rpc_unlink(char *);
void __rpc_purge_current_upcall(struct file *);
void __rpc_purge_one_upcall(struct file *filp, struct rpc_pipe_msg *target);
#endif
#endif
......@@ -369,3 +369,9 @@ rpcauth_uptodatecred(struct rpc_task *task)
(task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
}
int
rpcauth_deadcred(struct rpc_task *task)
{
return !(task->tk_msg.rpc_cred) ||
(task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_DEAD);
}
......@@ -156,7 +156,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
}
static struct gss_cl_ctx *
gss_cred_get_ctx(struct rpc_cred *cred)
gss_cred_get_uptodate_ctx(struct rpc_cred *cred)
{
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
struct gss_cl_ctx *ctx = NULL;
......@@ -206,9 +206,22 @@ dup_netobj(struct xdr_netobj *source, struct xdr_netobj *dest)
return 0;
}
static struct gss_cl_ctx *
gss_cred_get_ctx(struct rpc_cred *cred)
{
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
struct gss_cl_ctx *ctx = NULL;
read_lock(&gss_ctx_lock);
if (gss_cred->gc_ctx)
ctx = gss_get_ctx(gss_cred->gc_ctx);
read_unlock(&gss_ctx_lock);
return ctx;
}
static int
gss_parse_init_downcall(struct gss_api_mech *gm, struct xdr_netobj *buf,
struct gss_cl_ctx **gc, uid_t *uid)
struct gss_cl_ctx **gc, uid_t *uid, int *gss_err)
{
char *end = buf->data + buf->len;
char *p = buf->data;
......@@ -231,8 +244,17 @@ gss_parse_init_downcall(struct gss_api_mech *gm, struct xdr_netobj *buf,
/* FIXME: discarded timeout for now */
if (simple_get_bytes(&p, end, &timeout, sizeof(timeout)))
goto err_free_ctx;
*gss_err = 0;
if (simple_get_bytes(&p, end, &ctx->gc_win, sizeof(ctx->gc_win)))
goto err_free_ctx;
/* gssd signals an error by passing ctx->gc_win = 0: */
if (!ctx->gc_win) {
/* in which case the next int is an error code: */
if (simple_get_bytes(&p, end, gss_err, sizeof(*gss_err)))
goto err_free_ctx;
err = 0;
goto err_free_ctx;
}
if (simple_get_netobj(&p, end, &tmp_buf))
goto err_free_ctx;
if (dup_netobj(&tmp_buf, &ctx->gc_wire_ctx)) {
......@@ -261,6 +283,7 @@ gss_parse_init_downcall(struct gss_api_mech *gm, struct xdr_netobj *buf,
struct gss_upcall_msg {
struct rpc_pipe_msg msg;
struct list_head list;
struct gss_auth *auth;
struct rpc_wait_queue waitq;
uid_t uid;
atomic_t count;
......@@ -296,8 +319,6 @@ gss_release_callback(struct rpc_task *task)
gss_msg = gss_find_upcall(gss_auth, task->tk_msg.rpc_cred->cr_uid);
if (gss_msg) {
rpc_wake_up(&gss_msg->waitq);
list_del(&gss_msg->list);
gss_release_msg(gss_msg);
}
spin_unlock(&gss_auth->lock);
}
......@@ -328,19 +349,24 @@ gss_upcall(struct rpc_clnt *clnt, struct rpc_task *task, uid_t uid)
memset(gss_new, 0, sizeof(*gss_new));
INIT_LIST_HEAD(&gss_new->list);
INIT_RPC_WAITQ(&gss_new->waitq, "RPCSEC_GSS upcall waitq");
atomic_set(&gss_new->count, 2);
atomic_set(&gss_new->count, 1);
msg = &gss_new->msg;
msg->data = &gss_new->uid;
msg->len = sizeof(gss_new->uid);
gss_new->uid = uid;
gss_new->auth = gss_auth;
list_add(&gss_new->list, &gss_auth->upcalls);
gss_new = NULL;
task->tk_timeout = 5 * HZ;
rpc_sleep_on(&gss_msg->waitq, task, gss_release_callback, NULL);
spin_unlock(&gss_auth->lock);
res = rpc_queue_upcall(dentry->d_inode, msg);
spin_lock(&gss_auth->lock);
if (res)
if (res) {
rpc_wake_up(&gss_msg->waitq);
list_del(&gss_msg->list);
gss_release_msg(gss_msg);
}
return res;
out_sleep:
rpc_sleep_on(&gss_msg->waitq, task, NULL, NULL);
......@@ -354,13 +380,12 @@ gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
char *dst, size_t buflen)
{
char *data = (char *)msg->data + msg->copied;
ssize_t mlen = msg->len - msg->copied;
ssize_t mlen = msg->len;
ssize_t left;
if (mlen > buflen)
mlen = buflen;
left = copy_to_user(dst, data, mlen);
msg->copied += mlen - left;
return mlen - left;
}
......@@ -381,9 +406,10 @@ gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
struct auth_cred acred = { 0 };
struct rpc_cred *cred;
struct gss_upcall_msg *gss_msg;
struct gss_cl_ctx *ctx;
struct gss_cl_ctx *ctx = NULL;
ssize_t left;
int err;
int gss_err;
if (mlen > sizeof(buf))
return -ENOSPC;
......@@ -395,23 +421,30 @@ gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
auth = clnt->cl_auth;
gss_auth = container_of(auth, struct gss_auth, rpc_auth);
mech = gss_auth->mech;
err = gss_parse_init_downcall(mech, &obj, &ctx, &acred.uid);
err = gss_parse_init_downcall(mech, &obj, &ctx, &acred.uid, &gss_err);
if (err)
goto err;
cred = rpcauth_lookup_credcache(auth, &acred, 0);
if (!cred)
goto err_release_ctx;
goto err;
if (gss_err)
cred->cr_flags |= RPCAUTH_CRED_DEAD;
else
gss_cred_set_ctx(cred, ctx);
spin_lock(&gss_auth->lock);
gss_msg = gss_find_upcall(gss_auth, acred.uid);
if (gss_msg)
if (gss_msg) {
list_del(&gss_msg->list);
__rpc_purge_one_upcall(filp, &gss_msg->msg);
rpc_wake_up(&gss_msg->waitq);
gss_release_msg(gss_msg);
}
spin_unlock(&gss_auth->lock);
rpc_release_client(clnt);
return mlen;
err_release_ctx:
gss_destroy_ctx(ctx);
err:
if (ctx)
gss_destroy_ctx(ctx);
rpc_release_client(clnt);
dprintk("RPC: gss_pipe_downcall returning %d\n", err);
return err;
......@@ -421,9 +454,13 @@ void
gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
{
struct gss_upcall_msg *gss_msg = container_of(msg, struct gss_upcall_msg, msg);
struct gss_auth *gss_auth = gss_msg->auth;
spin_lock(&gss_auth->lock);
list_del(&gss_msg->list);
rpc_wake_up(&gss_msg->waitq);
gss_release_msg(gss_msg);
spin_unlock(&gss_auth->lock);
}
/*
......@@ -459,7 +496,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s",
clnt->cl_pathname,
gss_auth->mech->gm_ops->name);
gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops);
gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
if (IS_ERR(gss_auth->dentry))
goto err_free;
......@@ -637,7 +674,7 @@ gss_refresh(struct rpc_task *task)
task->tk_timeout = xprt->timeout.to_current;
spin_lock(&gss_auth->lock);
if (gss_cred_get_ctx(cred))
if (gss_cred_get_uptodate_ctx(cred))
goto out;
err = gss_upcall(clnt, task, cred->cr_uid);
out:
......@@ -648,8 +685,8 @@ gss_refresh(struct rpc_task *task)
static u32 *
gss_validate(struct rpc_task *task, u32 *p)
{
struct gss_cred *cred = (struct gss_cred *)task->tk_msg.rpc_cred;
struct gss_cl_ctx *ctx = cred->gc_ctx;
struct rpc_cred *cred = task->tk_msg.rpc_cred;
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
u32 seq, qop_state;
struct xdr_netobj bufin;
struct xdr_netobj bufout;
......
......@@ -190,33 +190,33 @@ gss_import_sec_context(struct xdr_netobj *input_token,
->gss_import_sec_context(input_token, *ctx_id);
}
/* gss_verify_mic: hash messages_buffer and return gss verify token. */
/* gss_get_mic: compute a mic over message and return mic_token. */
u32
gss_get_mic(struct gss_ctx *context_handle,
u32 qop,
struct xdr_netobj *message_buffer,
struct xdr_netobj *message_token)
struct xdr_netobj *message,
struct xdr_netobj *mic_token)
{
return context_handle->mech_type->gm_ops
->gss_get_mic(context_handle,
qop,
message_buffer,
message_token);
message,
mic_token);
}
/* gss_verify_mic: hash messages_buffer and return gss verify token. */
/* gss_verify_mic: check whether the provided mic_token verifies message. */
u32
gss_verify_mic(struct gss_ctx *context_handle,
struct xdr_netobj *signbuf,
struct xdr_netobj *checksum,
struct xdr_netobj *message,
struct xdr_netobj *mic_token,
u32 *qstate)
{
return context_handle->mech_type->gm_ops
->gss_verify_mic(context_handle,
signbuf,
checksum,
message,
mic_token,
qstate);
}
......
......@@ -850,17 +850,16 @@ call_refreshresult(struct rpc_task *task)
task->tk_status = 0;
task->tk_action = call_reserve;
if (status >= 0)
if (status >= 0 && rpcauth_uptodatecred(task))
return;
switch (status) {
case -EPIPE:
rpc_delay(task, 3*HZ);
case -ETIMEDOUT:
task->tk_action = call_refresh;
break;
default:
if (rpcauth_deadcred(task)) {
rpc_exit(task, -EACCES);
return;
}
task->tk_action = call_refresh;
if (status != -ETIMEDOUT)
rpc_delay(task, 3*HZ);
return;
}
/*
......@@ -909,6 +908,8 @@ call_verify(struct rpc_task *task)
switch ((n = ntohl(*p++))) {
case RPC_AUTH_REJECTEDCRED:
case RPC_AUTH_REJECTEDVERF:
case RPCSEC_GSS_CREDPROBLEM:
case RPCSEC_GSS_CTXPROBLEM:
if (!task->tk_cred_retry)
break;
task->tk_cred_retry--;
......
......@@ -75,6 +75,28 @@ __rpc_purge_current_upcall(struct file *filp)
msg->errno = 0;
}
void
__rpc_purge_one_upcall(struct file *filp, struct rpc_pipe_msg *target)
{
struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
struct rpc_pipe_msg *msg;
msg = filp->private_data;
if (msg == target) {
filp->private_data = NULL;
goto found;
}
list_for_each_entry(msg, &rpci->pipe, list) {
if (msg == target) {
list_del(&msg->list);
goto found;
}
}
BUG();
found:
return;
}
int
rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
{
......@@ -82,7 +104,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
int res = 0;
down(&inode->i_sem);
if (rpci->nreaders) {
if (rpci->nreaders || (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN)) {
list_add_tail(&msg->list, &rpci->pipe);
rpci->pipelen += msg->len;
} else
......@@ -149,7 +171,7 @@ rpc_pipe_release(struct inode *inode, struct file *filp)
down(&inode->i_sem);
if (filp->f_mode & FMODE_READ)
rpci->nreaders --;
if (!rpci->nreaders)
if (!rpci->nreaders && !(rpci->flags & RPC_PIPE_WAIT_FOR_OPEN))
__rpc_purge_upcall(inode, -EPIPE);
up(&inode->i_sem);
return 0;
......@@ -273,6 +295,8 @@ rpc_show_info(struct seq_file *m, void *v)
clnt->cl_prog, clnt->cl_vers);
seq_printf(m, "address: %u.%u.%u.%u\n",
NIPQUAD(clnt->cl_xprt->addr.sin_addr.s_addr));
seq_printf(m, "protocol: %s\n",
clnt->cl_xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
return 0;
}
......@@ -644,7 +668,7 @@ rpc_rmdir(char *path)
}
struct dentry *
rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops)
rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
{
struct nameidata nd;
struct dentry *dentry;
......@@ -663,6 +687,7 @@ rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops)
d_instantiate(dentry, inode);
rpci = RPC_I(inode);
rpci->private = private;
rpci->flags = flags;
rpci->ops = ops;
inode_dir_notify(dir, DN_CREATE);
out:
......
......@@ -57,6 +57,7 @@ EXPORT_SYMBOL(rpc_wake_up);
EXPORT_SYMBOL(rpc_queue_upcall);
EXPORT_SYMBOL(rpc_mkpipe);
EXPORT_SYMBOL(__rpc_purge_current_upcall);
EXPORT_SYMBOL(__rpc_purge_one_upcall);
/* Client transport */
EXPORT_SYMBOL(xprt_create_proto);
......
......@@ -679,6 +679,7 @@ udp_data_ready(struct sock *sk, int len)
struct rpc_rqst *rovr;
struct sk_buff *skb;
int err, repsize, copied;
u32 xid;
read_lock(&sk->sk_callback_lock);
dprintk("RPC: udp_data_ready...\n");
......@@ -701,16 +702,18 @@ udp_data_ready(struct sock *sk, int len)
goto dropit;
}
/* Copy the XID from the skb... */
if (skb_copy_bits(skb, sizeof(struct udphdr), &xid, sizeof(xid)) < 0)
goto dropit;
/* Look up and lock the request corresponding to the given XID */
spin_lock(&xprt->sock_lock);
rovr = xprt_lookup_rqst(xprt, *(u32 *) (skb->h.raw + sizeof(struct udphdr)));
rovr = xprt_lookup_rqst(xprt, xid);
if (!rovr)
goto out_unlock;
task = rovr->rq_task;
dprintk("RPC: %4d received reply\n", task->tk_pid);
xprt_pktdump("packet data:",
(u32 *) (skb->h.raw+sizeof(struct udphdr)), repsize);
if ((copied = rovr->rq_rlen) > repsize)
copied = repsize;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment