libceph: add update_authorizer auth method
authorSage Weil <sage@inktank.com>
Mon, 25 Mar 2013 17:26:01 +0000 (10:26 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 20 Jun 2013 18:58:46 +0000 (11:58 -0700)
commit 0bed9b5c523d577378b6f83eab5835fe30c27208 upstream.

Currently the messenger calls out to a get_authorizer con op, which will
create a new authorizer if it doesn't yet have one.  In the meantime, when
we rotate our service keys, the authorizer doesn't get updated.  Eventually
it will be rejected by the server on a new connection attempt and get
invalidated, and we will then rebuild a new authorizer, but this is not
ideal.

Instead, if we do have an authorizer, call a new update_authorizer op that
will verify that the current authorizer is using the latest secret.  If it
is not, we will build a new one that does.  This avoids the transient
failure.

This fixes one of the sorry sequence of events for bug

http://tracker.ceph.com/issues/4282

Signed-off-by: Sage Weil <sage@inktank.com>
Reviewed-by: Alex Elder <elder@inktank.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ceph/mds_client.c
include/linux/ceph/auth.h
net/ceph/auth_x.c
net/ceph/auth_x.h
net/ceph/osd_client.c

index f8a646268525eadb011f8768f50f84b1ebcd38d2..e0b38223a32cc8ab4148ff4354c37621f06864bd 100644 (file)
@@ -3425,7 +3425,12 @@ static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con,
        }
        if (!auth->authorizer && ac->ops && ac->ops->create_authorizer) {
                int ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_MDS,
-                                                       auth);
+                                                    auth);
+               if (ret)
+                       return ERR_PTR(ret);
+       } else if (ac->ops && ac->ops_update_authorizer) {
+               int ret = ac->ops->update_authorizer(ac, CEPH_ENTITY_TYPE_MDS,
+                                                    auth);
                if (ret)
                        return ERR_PTR(ret);
        }
index d4080f309b5699d5fbaa5dbe96d38a1977be7693..73e973e7002664c0bbe87d77322f08018f6f6d2a 100644 (file)
@@ -52,6 +52,9 @@ struct ceph_auth_client_ops {
         */
        int (*create_authorizer)(struct ceph_auth_client *ac, int peer_type,
                                 struct ceph_auth_handshake *auth);
+       /* ensure that an existing authorizer is up to date */
+       int (*update_authorizer)(struct ceph_auth_client *ac, int peer_type,
+                                struct ceph_auth_handshake *auth);
        int (*verify_authorizer_reply)(struct ceph_auth_client *ac,
                                       struct ceph_authorizer *a, size_t len);
        void (*destroy_authorizer)(struct ceph_auth_client *ac,
index bd8758dbfded1d2d8db1feb0fee68127f0d30146..2d5981555cd6dcb9e5ae2485cc56462ccf46a32f 100644 (file)
@@ -298,6 +298,7 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
                        return -ENOMEM;
        }
        au->service = th->service;
+       au->secret_id = th->secret_id;
 
        msg_a = au->buf->vec.iov_base;
        msg_a->struct_v = 1;
@@ -555,6 +556,27 @@ static int ceph_x_create_authorizer(
        return 0;
 }
 
+static int ceph_x_update_authorizer(
+       struct ceph_auth_client *ac, int peer_type,
+       struct ceph_auth_handshake *auth)
+{
+       struct ceph_x_authorizer *au;
+       struct ceph_x_ticket_handler *th;
+       int ret;
+
+       th = get_ticket_handler(ac, peer_type);
+       if (IS_ERR(th))
+               return PTR_ERR(th);
+
+       au = (struct ceph_x_authorizer *)auth->authorizer;
+       if (au->secret_id < th->secret_id) {
+               dout("ceph_x_update_authorizer service %u secret %llu < %llu\n",
+                    au->service, au->secret_id, th->secret_id);
+               return ceph_x_build_authorizer(ac, th, au);
+       }
+       return 0;
+}
+
 static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac,
                                          struct ceph_authorizer *a, size_t len)
 {
@@ -641,6 +663,7 @@ static const struct ceph_auth_client_ops ceph_x_ops = {
        .build_request = ceph_x_build_request,
        .handle_reply = ceph_x_handle_reply,
        .create_authorizer = ceph_x_create_authorizer,
+       .update_authorizer = ceph_x_update_authorizer,
        .verify_authorizer_reply = ceph_x_verify_authorizer_reply,
        .destroy_authorizer = ceph_x_destroy_authorizer,
        .invalidate_authorizer = ceph_x_invalidate_authorizer,
index e02da7a5c5a1052b881f383e7fca318da0675421..5c2ad4e12c516a15507969e28f3514e3d915b7c6 100644 (file)
@@ -29,6 +29,7 @@ struct ceph_x_authorizer {
        struct ceph_buffer *buf;
        unsigned service;
        u64 nonce;
+       u64 secret_id;
        char reply_buf[128];  /* big enough for encrypted blob */
 };
 
index 2e54e57708b40db3d00f38dd8dca5c8518b03ec6..9eeb98c05bdf13813eba092289ed8cf3cd9fb18f 100644 (file)
@@ -2136,6 +2136,11 @@ static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con,
                                                        auth);
                if (ret)
                        return ERR_PTR(ret);
+       } else if (ac->ops && ac->ops->update_authorizer) {
+               int ret = ac->ops->update_authorizer(ac, CEPH_ENTITY_TYPE_OSD,
+                                                    auth);
+               if (ret)
+                       return ERR_PTR(ret);
        }
        *proto = ac->protocol;