ceph: allow renewal of auth credentials
Add infrastructure to allow the mon_client to periodically renew its auth
credentials. Also add a messenger callback that will force such a renewal
if a peer rejects our authenticator.
Signed-off-by: Yehuda Sadeh <yehuda@hq.newdream.net>
Signed-off-by: Sage Weil <sage@newdream.net>
diff --git a/fs/ceph/auth.c b/fs/ceph/auth.c
index 32f2e2a..d5872d4 100644
--- a/fs/ceph/auth.c
+++ b/fs/ceph/auth.c
@@ -125,6 +125,30 @@
return -ERANGE;
}
+int ceph_build_auth_request(struct ceph_auth_client *ac,
+ void *msg_buf, size_t msg_len)
+{
+ struct ceph_mon_request_header *monhdr = msg_buf;
+ void *p = monhdr + 1;
+ void *end = msg_buf + msg_len;
+ int ret;
+
+ monhdr->have_version = 0;
+ monhdr->session_mon = cpu_to_le16(-1);
+ monhdr->session_mon_tid = 0;
+
+ ceph_encode_32(&p, ac->protocol);
+
+ ret = ac->ops->build_request(ac, p + sizeof(u32), end);
+ if (ret < 0) {
+ pr_err("error %d building request\n", ret);
+ return ret;
+ }
+ dout(" built request %d bytes\n", ret);
+ ceph_encode_32(&p, ret);
+ return p + ret - msg_buf;
+}
+
/*
* Handle auth message from monitor.
*/
@@ -188,28 +212,13 @@
goto out;
}
}
+
+ ac->negotiating = false;
}
ret = ac->ops->handle_reply(ac, result, payload, payload_end);
if (ret == -EAGAIN) {
- struct ceph_mon_request_header *monhdr = reply_buf;
- void *p = reply_buf + 1;
- void *end = reply_buf + reply_len;
-
- monhdr->have_version = 0;
- monhdr->session_mon = cpu_to_le16(-1);
- monhdr->session_mon_tid = 0;
-
- ceph_encode_32(&p, ac->protocol);
-
- ret = ac->ops->build_request(ac, p + sizeof(u32), end);
- if (ret < 0) {
- pr_err("error %d building request\n", ret);
- goto out;
- }
- dout(" built request %d bytes\n", ret);
- ceph_encode_32(&p, ret);
- return p + ret - reply_buf;
+ return ceph_build_auth_request(ac, reply_buf, reply_len);
} else if (ret) {
pr_err("authentication error %d\n", ret);
return ret;
@@ -222,4 +231,20 @@
return ret;
}
+int ceph_build_auth(struct ceph_auth_client *ac,
+ void *msg_buf, size_t msg_len)
+{
+ if (!ac->protocol)
+ return ceph_auth_build_hello(ac, msg_buf, msg_len);
+ BUG_ON(!ac->ops);
+ if (!ac->ops->is_authenticated(ac))
+ return ceph_build_auth_request(ac, msg_buf, msg_len);
+ return 0;
+}
+int ceph_auth_is_authenticated(struct ceph_auth_client *ac)
+{
+ if (!ac->ops)
+ return 0;
+ return ac->ops->is_authenticated(ac);
+}
diff --git a/fs/ceph/auth.h b/fs/ceph/auth.h
index 4d8cdf6..ca4f57c 100644
--- a/fs/ceph/auth.h
+++ b/fs/ceph/auth.h
@@ -42,6 +42,8 @@
struct ceph_authorizer *a, size_t len);
void (*destroy_authorizer)(struct ceph_auth_client *ac,
struct ceph_authorizer *a);
+ void (*invalidate_authorizer)(struct ceph_auth_client *ac,
+ int peer_type);
/* reset when we (re)connect to a monitor */
void (*reset)(struct ceph_auth_client *ac);
@@ -74,4 +76,9 @@
void *reply_buf, size_t reply_len);
extern int ceph_entity_name_encode(const char *name, void **p, void *end);
+extern int ceph_build_auth(struct ceph_auth_client *ac,
+ void *msg_buf, size_t msg_len);
+
+extern int ceph_auth_is_authenticated(struct ceph_auth_client *ac);
+
#endif
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 4e3e8b2..aa8506b 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -2946,12 +2946,25 @@
return ac->ops->verify_authorizer_reply(ac, s->s_authorizer, len);
}
+static int invalidate_authorizer(struct ceph_connection *con)
+{
+ struct ceph_mds_session *s = con->private;
+ struct ceph_mds_client *mdsc = s->s_mdsc;
+ struct ceph_auth_client *ac = mdsc->client->monc.auth;
+
+ if (ac->ops->invalidate_authorizer)
+ ac->ops->invalidate_authorizer(ac, CEPH_ENTITY_TYPE_MDS);
+
+ return ceph_monc_validate_auth(&mdsc->client->monc);
+}
+
const static struct ceph_connection_operations mds_con_ops = {
.get = con_get,
.put = con_put,
.dispatch = dispatch,
.get_authorizer = get_authorizer,
.verify_authorizer_reply = verify_authorizer_reply,
+ .invalidate_authorizer = invalidate_authorizer,
.peer_reset = peer_reset,
};
diff --git a/fs/ceph/messenger.c b/fs/ceph/messenger.c
index e4e8d44..c434178 100644
--- a/fs/ceph/messenger.c
+++ b/fs/ceph/messenger.c
@@ -1849,6 +1849,15 @@
con->in_msg = NULL;
}
+ /*
+ * in case we faulted due to authentication, invalidate our
+ * current tickets so that we can get new ones.
+ */
+ if (con->auth_retry && con->ops->invalidate_authorizer) {
+ dout("calling invalidate_authorizer()\n");
+ con->ops->invalidate_authorizer(con);
+ }
+
/* If there are no messages in the queue, place the connection
* in a STANDBY state (i.e., don't try to reconnect just yet). */
if (list_empty(&con->out_queue) && !con->out_keepalive_pending) {
diff --git a/fs/ceph/messenger.h b/fs/ceph/messenger.h
index c26a3d8..c973537 100644
--- a/fs/ceph/messenger.h
+++ b/fs/ceph/messenger.h
@@ -32,6 +32,7 @@
void **buf, int *len, int *proto,
void **reply_buf, int *reply_len, int force_new);
int (*verify_authorizer_reply) (struct ceph_connection *con, int len);
+ int (*invalidate_authorizer)(struct ceph_connection *con);
/* protocol version mismatch */
void (*bad_proto) (struct ceph_connection *con);
diff --git a/fs/ceph/mon_client.c b/fs/ceph/mon_client.c
index 3f7ae7f..fec41a0 100644
--- a/fs/ceph/mon_client.c
+++ b/fs/ceph/mon_client.c
@@ -29,6 +29,8 @@
const static struct ceph_connection_operations mon_con_ops;
+static int __validate_auth(struct ceph_mon_client *monc);
+
/*
* Decode a monmap blob (e.g., during mount).
*/
@@ -103,6 +105,7 @@
ceph_con_revoke(monc->con, monc->m_auth);
ceph_con_close(monc->con);
monc->cur_mon = -1;
+ monc->pending_auth = 0;
ceph_auth_reset(monc->auth);
}
}
@@ -334,7 +337,7 @@
out:
mutex_unlock(&monc->mutex);
- wake_up(&client->mount_wq);
+ wake_up(&client->auth_wq);
}
/*
@@ -477,6 +480,11 @@
__open_session(monc); /* continue hunting */
} else {
ceph_con_keepalive(monc->con);
+ mutex_unlock(&monc->mutex);
+
+ __validate_auth(monc);
+
+ mutex_lock(&monc->mutex);
if (monc->auth->ops->is_authenticated(monc->auth))
__send_subscribe(monc);
}
@@ -557,6 +565,7 @@
goto out_pool2;
monc->m_auth = ceph_msg_new(CEPH_MSG_AUTH, 4096, 0, 0, NULL);
+ monc->pending_auth = 0;
if (IS_ERR(monc->m_auth)) {
err = PTR_ERR(monc->m_auth);
monc->m_auth = NULL;
@@ -614,6 +623,15 @@
kfree(monc->monmap);
}
+static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len)
+{
+ monc->pending_auth = 1;
+ monc->m_auth->front.iov_len = len;
+ monc->m_auth->hdr.front_len = cpu_to_le32(len);
+ ceph_msg_get(monc->m_auth); /* keep our ref */
+ ceph_con_send(monc->con, monc->m_auth);
+}
+
static void handle_auth_reply(struct ceph_mon_client *monc,
struct ceph_msg *msg)
@@ -621,18 +639,16 @@
int ret;
mutex_lock(&monc->mutex);
+ monc->pending_auth = 0;
ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base,
msg->front.iov_len,
monc->m_auth->front.iov_base,
monc->m_auth->front_max);
if (ret < 0) {
- monc->client->mount_err = ret;
- wake_up(&monc->client->mount_wq);
+ monc->client->auth_err = ret;
+ wake_up(&monc->client->auth_wq);
} else if (ret > 0) {
- monc->m_auth->front.iov_len = ret;
- monc->m_auth->hdr.front_len = cpu_to_le32(ret);
- ceph_msg_get(monc->m_auth); /* keep our ref */
- ceph_con_send(monc->con, monc->m_auth);
+ __send_prepared_auth_request(monc, ret);
} else if (monc->auth->ops->is_authenticated(monc->auth)) {
dout("authenticated, starting session\n");
@@ -645,6 +661,31 @@
mutex_unlock(&monc->mutex);
}
+static int __validate_auth(struct ceph_mon_client *monc)
+{
+ int ret;
+
+ if (monc->pending_auth)
+ return 0;
+
+ ret = ceph_build_auth(monc->auth, monc->m_auth->front.iov_base,
+ monc->m_auth->front_max);
+ if (ret <= 0)
+ return ret; /* either an error, or no need to authenticate */
+ __send_prepared_auth_request(monc, ret);
+ return 0;
+}
+
+int ceph_monc_validate_auth(struct ceph_mon_client *monc)
+{
+ int ret;
+
+ mutex_lock(&monc->mutex);
+ ret = __validate_auth(monc);
+ mutex_unlock(&monc->mutex);
+ return ret;
+}
+
/*
* handle incoming message
*/
diff --git a/fs/ceph/mon_client.h b/fs/ceph/mon_client.h
index c75b533..5ca8e48 100644
--- a/fs/ceph/mon_client.h
+++ b/fs/ceph/mon_client.h
@@ -61,6 +61,7 @@
struct ceph_auth_client *auth;
struct ceph_msg *m_auth;
+ int pending_auth;
bool hunting;
int cur_mon; /* last monitor i contacted */
@@ -110,6 +111,8 @@
extern int ceph_monc_open_session(struct ceph_mon_client *monc);
+extern int ceph_monc_validate_auth(struct ceph_mon_client *monc);
+
#endif
diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c
index 944759b..35c8afe 100644
--- a/fs/ceph/osd_client.c
+++ b/fs/ceph/osd_client.c
@@ -1448,6 +1448,17 @@
return ac->ops->verify_authorizer_reply(ac, o->o_authorizer, len);
}
+static int invalidate_authorizer(struct ceph_connection *con)
+{
+ struct ceph_osd *o = con->private;
+ struct ceph_osd_client *osdc = o->o_osdc;
+ struct ceph_auth_client *ac = osdc->client->monc.auth;
+
+ if (ac->ops->invalidate_authorizer)
+ ac->ops->invalidate_authorizer(ac, CEPH_ENTITY_TYPE_OSD);
+
+ return ceph_monc_validate_auth(&osdc->client->monc);
+}
const static struct ceph_connection_operations osd_con_ops = {
.get = get_osd_con,
@@ -1455,6 +1466,7 @@
.dispatch = dispatch,
.get_authorizer = get_authorizer,
.verify_authorizer_reply = verify_authorizer_reply,
+ .invalidate_authorizer = invalidate_authorizer,
.alloc_msg = alloc_msg,
.fault = osd_reset,
};
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index cd81c84..3a25489 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -542,7 +542,7 @@
mutex_init(&client->mount_mutex);
- init_waitqueue_head(&client->mount_wq);
+ init_waitqueue_head(&client->auth_wq);
client->sb = NULL;
client->mount_state = CEPH_MOUNT_MOUNTING;
@@ -550,7 +550,7 @@
client->msgr = NULL;
- client->mount_err = 0;
+ client->auth_err = 0;
atomic_long_set(&client->writeback_count, 0);
err = bdi_init(&client->backing_dev_info);
@@ -742,13 +742,13 @@
/* wait */
dout("mount waiting for mon_map\n");
- err = wait_event_interruptible_timeout(client->mount_wq, /* FIXME */
- have_mon_map(client) || (client->mount_err < 0),
+ err = wait_event_interruptible_timeout(client->auth_wq,
+ have_mon_map(client) || (client->auth_err < 0),
timeout);
if (err == -EINTR || err == -ERESTARTSYS)
goto out;
- if (client->mount_err < 0) {
- err = client->mount_err;
+ if (client->auth_err < 0) {
+ err = client->auth_err;
goto out;
}
}
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 62d9ae48..770f7b5 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -123,9 +123,9 @@
struct super_block *sb;
unsigned long mount_state;
- wait_queue_head_t mount_wq;
+ wait_queue_head_t auth_wq;
- int mount_err;
+ int auth_err;
struct ceph_messenger *msgr; /* messenger instance */
struct ceph_mon_client monc;