Skip to content

Commit

Permalink
rpc: implement new upcall
Browse files Browse the repository at this point in the history
Implement the new upcall.  We decide which version of the upcall gssd
will use (new or old), by creating both pipes (the new one named "gssd",
the old one named after the mechanism (e.g., "krb5")), and then waiting
to see which version gssd actually opens.

We don't permit pipes of the two different types to be opened at once.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
\"J. Bruce Fields\ authored and Trond Myklebust committed Dec 23, 2008
1 parent 5b7ddd4 commit 34769fc
Showing 1 changed file with 96 additions and 20 deletions.
116 changes: 96 additions & 20 deletions net/sunrpc/auth_gss/auth_gss.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,13 @@ struct gss_auth {
struct gss_api_mech *mech;
enum rpc_gss_svc service;
struct rpc_clnt *client;
struct dentry *dentry;
/*
* There are two upcall pipes; dentry[1], named "gssd", is used
* for the new text-based upcall; dentry[0] is named after the
* mechanism (for example, "krb5") and exists for
* backwards-compatibility with older gssd's.
*/
struct dentry *dentry[2];
};

/* pipe_version >= 0 if and only if someone has a pipe open. */
Expand All @@ -83,7 +89,8 @@ static struct rpc_wait_queue pipe_version_rpc_waitqueue;
static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);

static void gss_free_ctx(struct gss_cl_ctx *);
static struct rpc_pipe_ops gss_upcall_ops;
static struct rpc_pipe_ops gss_upcall_ops_v0;
static struct rpc_pipe_ops gss_upcall_ops_v1;

static inline struct gss_cl_ctx *
gss_get_ctx(struct gss_cl_ctx *ctx)
Expand Down Expand Up @@ -227,6 +234,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
return p;
}

#define UPCALL_BUF_LEN 128

struct gss_upcall_msg {
atomic_t count;
Expand All @@ -238,6 +246,7 @@ struct gss_upcall_msg {
struct rpc_wait_queue rpc_waitqueue;
wait_queue_head_t waitqueue;
struct gss_cl_ctx *ctx;
char databuf[UPCALL_BUF_LEN];
};

static int get_pipe_version(void)
Expand All @@ -247,7 +256,7 @@ static int get_pipe_version(void)
spin_lock(&pipe_version_lock);
if (pipe_version >= 0) {
atomic_inc(&pipe_users);
ret = 0;
ret = pipe_version;
} else
ret = -EAGAIN;
spin_unlock(&pipe_version_lock);
Expand Down Expand Up @@ -353,6 +362,29 @@ gss_upcall_callback(struct rpc_task *task)
gss_release_msg(gss_msg);
}

static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)
{
gss_msg->msg.data = &gss_msg->uid;
gss_msg->msg.len = sizeof(gss_msg->uid);
}

static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg)
{
gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d\n",
gss_msg->auth->mech->gm_name,
gss_msg->uid);
gss_msg->msg.data = gss_msg->databuf;
BUG_ON(gss_msg->msg.len > UPCALL_BUF_LEN);
}

static void gss_encode_msg(struct gss_upcall_msg *gss_msg)
{
if (pipe_version == 0)
gss_encode_v0_msg(gss_msg);
else /* pipe_version == 1 */
gss_encode_v1_msg(gss_msg);
}

static inline struct gss_upcall_msg *
gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid)
{
Expand All @@ -367,15 +399,14 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid)
kfree(gss_msg);
return ERR_PTR(vers);
}
gss_msg->inode = RPC_I(gss_auth->dentry->d_inode);
gss_msg->inode = RPC_I(gss_auth->dentry[vers]->d_inode);
INIT_LIST_HEAD(&gss_msg->list);
rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
init_waitqueue_head(&gss_msg->waitqueue);
atomic_set(&gss_msg->count, 1);
gss_msg->msg.data = &gss_msg->uid;
gss_msg->msg.len = sizeof(gss_msg->uid);
gss_msg->uid = uid;
gss_msg->auth = gss_auth;
gss_encode_msg(gss_msg);
return gss_msg;
}

Expand Down Expand Up @@ -613,18 +644,36 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
return err;
}

static int
gss_pipe_open(struct inode *inode)
static int gss_pipe_open(struct inode *inode, int new_version)
{
int ret = 0;

spin_lock(&pipe_version_lock);
if (pipe_version < 0) {
pipe_version = 0;
/* First open of any gss pipe determines the version: */
pipe_version = new_version;
rpc_wake_up(&pipe_version_rpc_waitqueue);
wake_up(&pipe_version_waitqueue);
} else if (pipe_version != new_version) {
/* Trying to open a pipe of a different version */
ret = -EBUSY;
goto out;
}
atomic_inc(&pipe_users);
out:
spin_unlock(&pipe_version_lock);
return 0;
return ret;

}

static int gss_pipe_open_v0(struct inode *inode)
{
return gss_pipe_open(inode, 0);
}

static int gss_pipe_open_v1(struct inode *inode)
{
return gss_pipe_open(inode, 1);
}

static void
Expand Down Expand Up @@ -702,20 +751,38 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
atomic_set(&auth->au_count, 1);
kref_init(&gss_auth->kref);

gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name,
clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
if (IS_ERR(gss_auth->dentry)) {
err = PTR_ERR(gss_auth->dentry);
/*
* Note: if we created the old pipe first, then someone who
* examined the directory at the right moment might conclude
* that we supported only the old pipe. So we instead create
* the new pipe first.
*/
gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_dentry,
"gssd",
clnt, &gss_upcall_ops_v1,
RPC_PIPE_WAIT_FOR_OPEN);
if (IS_ERR(gss_auth->dentry[1])) {
err = PTR_ERR(gss_auth->dentry[1]);
goto err_put_mech;
}

gss_auth->dentry[0] = rpc_mkpipe(clnt->cl_dentry,
gss_auth->mech->gm_name,
clnt, &gss_upcall_ops_v0,
RPC_PIPE_WAIT_FOR_OPEN);
if (IS_ERR(gss_auth->dentry[0])) {
err = PTR_ERR(gss_auth->dentry[0]);
goto err_unlink_pipe_1;
}
err = rpcauth_init_credcache(auth);
if (err)
goto err_unlink_pipe;
goto err_unlink_pipe_0;

return auth;
err_unlink_pipe:
rpc_unlink(gss_auth->dentry);
err_unlink_pipe_0:
rpc_unlink(gss_auth->dentry[0]);
err_unlink_pipe_1:
rpc_unlink(gss_auth->dentry[1]);
err_put_mech:
gss_mech_put(gss_auth->mech);
err_free:
Expand All @@ -728,7 +795,8 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
static void
gss_free(struct gss_auth *gss_auth)
{
rpc_unlink(gss_auth->dentry);
rpc_unlink(gss_auth->dentry[1]);
rpc_unlink(gss_auth->dentry[0]);
gss_mech_put(gss_auth->mech);

kfree(gss_auth);
Expand Down Expand Up @@ -1419,11 +1487,19 @@ static const struct rpc_credops gss_nullops = {
.crunwrap_resp = gss_unwrap_resp,
};

static struct rpc_pipe_ops gss_upcall_ops = {
static struct rpc_pipe_ops gss_upcall_ops_v0 = {
.upcall = gss_pipe_upcall,
.downcall = gss_pipe_downcall,
.destroy_msg = gss_pipe_destroy_msg,
.open_pipe = gss_pipe_open_v0,
.release_pipe = gss_pipe_release,
};

static struct rpc_pipe_ops gss_upcall_ops_v1 = {
.upcall = gss_pipe_upcall,
.downcall = gss_pipe_downcall,
.destroy_msg = gss_pipe_destroy_msg,
.open_pipe = gss_pipe_open,
.open_pipe = gss_pipe_open_v1,
.release_pipe = gss_pipe_release,
};

Expand Down

0 comments on commit 34769fc

Please sign in to comment.