linux/net/ceph/auth_x.c
<<
>>
Prefs
   1
   2#include <linux/ceph/ceph_debug.h>
   3
   4#include <linux/err.h>
   5#include <linux/module.h>
   6#include <linux/random.h>
   7#include <linux/slab.h>
   8
   9#include <linux/ceph/decode.h>
  10#include <linux/ceph/auth.h>
  11#include <linux/ceph/libceph.h>
  12#include <linux/ceph/messenger.h>
  13
  14#include "crypto.h"
  15#include "auth_x.h"
  16#include "auth_x_protocol.h"
  17
  18static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed);
  19
  20static int ceph_x_is_authenticated(struct ceph_auth_client *ac)
  21{
  22        struct ceph_x_info *xi = ac->private;
  23        int need;
  24
  25        ceph_x_validate_tickets(ac, &need);
  26        dout("ceph_x_is_authenticated want=%d need=%d have=%d\n",
  27             ac->want_keys, need, xi->have_keys);
  28        return (ac->want_keys & xi->have_keys) == ac->want_keys;
  29}
  30
  31static int ceph_x_should_authenticate(struct ceph_auth_client *ac)
  32{
  33        struct ceph_x_info *xi = ac->private;
  34        int need;
  35
  36        ceph_x_validate_tickets(ac, &need);
  37        dout("ceph_x_should_authenticate want=%d need=%d have=%d\n",
  38             ac->want_keys, need, xi->have_keys);
  39        return need != 0;
  40}
  41
  42static int ceph_x_encrypt_offset(void)
  43{
  44        return sizeof(u32) + sizeof(struct ceph_x_encrypt_header);
  45}
  46
  47static int ceph_x_encrypt_buflen(int ilen)
  48{
  49        return ceph_x_encrypt_offset() + ilen + 16;
  50}
  51
  52static int ceph_x_encrypt(struct ceph_crypto_key *secret, void *buf,
  53                          int buf_len, int plaintext_len)
  54{
  55        struct ceph_x_encrypt_header *hdr = buf + sizeof(u32);
  56        int ciphertext_len;
  57        int ret;
  58
  59        hdr->struct_v = 1;
  60        hdr->magic = cpu_to_le64(CEPHX_ENC_MAGIC);
  61
  62        ret = ceph_crypt(secret, true, buf + sizeof(u32), buf_len - sizeof(u32),
  63                         plaintext_len + sizeof(struct ceph_x_encrypt_header),
  64                         &ciphertext_len);
  65        if (ret)
  66                return ret;
  67
  68        ceph_encode_32(&buf, ciphertext_len);
  69        return sizeof(u32) + ciphertext_len;
  70}
  71
  72static int ceph_x_decrypt(struct ceph_crypto_key *secret, void **p, void *end)
  73{
  74        struct ceph_x_encrypt_header *hdr = *p + sizeof(u32);
  75        int ciphertext_len, plaintext_len;
  76        int ret;
  77
  78        ceph_decode_32_safe(p, end, ciphertext_len, e_inval);
  79        ceph_decode_need(p, end, ciphertext_len, e_inval);
  80
  81        ret = ceph_crypt(secret, false, *p, end - *p, ciphertext_len,
  82                         &plaintext_len);
  83        if (ret)
  84                return ret;
  85
  86        if (hdr->struct_v != 1 || le64_to_cpu(hdr->magic) != CEPHX_ENC_MAGIC)
  87                return -EPERM;
  88
  89        *p += ciphertext_len;
  90        return plaintext_len - sizeof(struct ceph_x_encrypt_header);
  91
  92e_inval:
  93        return -EINVAL;
  94}
  95
  96/*
  97 * get existing (or insert new) ticket handler
  98 */
  99static struct ceph_x_ticket_handler *
 100get_ticket_handler(struct ceph_auth_client *ac, int service)
 101{
 102        struct ceph_x_ticket_handler *th;
 103        struct ceph_x_info *xi = ac->private;
 104        struct rb_node *parent = NULL, **p = &xi->ticket_handlers.rb_node;
 105
 106        while (*p) {
 107                parent = *p;
 108                th = rb_entry(parent, struct ceph_x_ticket_handler, node);
 109                if (service < th->service)
 110                        p = &(*p)->rb_left;
 111                else if (service > th->service)
 112                        p = &(*p)->rb_right;
 113                else
 114                        return th;
 115        }
 116
 117        /* add it */
 118        th = kzalloc(sizeof(*th), GFP_NOFS);
 119        if (!th)
 120                return ERR_PTR(-ENOMEM);
 121        th->service = service;
 122        rb_link_node(&th->node, parent, p);
 123        rb_insert_color(&th->node, &xi->ticket_handlers);
 124        return th;
 125}
 126
 127static void remove_ticket_handler(struct ceph_auth_client *ac,
 128                                  struct ceph_x_ticket_handler *th)
 129{
 130        struct ceph_x_info *xi = ac->private;
 131
 132        dout("remove_ticket_handler %p %d\n", th, th->service);
 133        rb_erase(&th->node, &xi->ticket_handlers);
 134        ceph_crypto_key_destroy(&th->session_key);
 135        if (th->ticket_blob)
 136                ceph_buffer_put(th->ticket_blob);
 137        kfree(th);
 138}
 139
 140static int process_one_ticket(struct ceph_auth_client *ac,
 141                              struct ceph_crypto_key *secret,
 142                              void **p, void *end)
 143{
 144        struct ceph_x_info *xi = ac->private;
 145        int type;
 146        u8 tkt_struct_v, blob_struct_v;
 147        struct ceph_x_ticket_handler *th;
 148        void *dp, *dend;
 149        int dlen;
 150        char is_enc;
 151        struct timespec validity;
 152        void *tp, *tpend;
 153        void **ptp;
 154        struct ceph_crypto_key new_session_key = { 0 };
 155        struct ceph_buffer *new_ticket_blob;
 156        unsigned long new_expires, new_renew_after;
 157        u64 new_secret_id;
 158        int ret;
 159
 160        ceph_decode_need(p, end, sizeof(u32) + 1, bad);
 161
 162        type = ceph_decode_32(p);
 163        dout(" ticket type %d %s\n", type, ceph_entity_type_name(type));
 164
 165        tkt_struct_v = ceph_decode_8(p);
 166        if (tkt_struct_v != 1)
 167                goto bad;
 168
 169        th = get_ticket_handler(ac, type);
 170        if (IS_ERR(th)) {
 171                ret = PTR_ERR(th);
 172                goto out;
 173        }
 174
 175        /* blob for me */
 176        dp = *p + ceph_x_encrypt_offset();
 177        ret = ceph_x_decrypt(secret, p, end);
 178        if (ret < 0)
 179                goto out;
 180        dout(" decrypted %d bytes\n", ret);
 181        dend = dp + ret;
 182
 183        tkt_struct_v = ceph_decode_8(&dp);
 184        if (tkt_struct_v != 1)
 185                goto bad;
 186
 187        ret = ceph_crypto_key_decode(&new_session_key, &dp, dend);
 188        if (ret)
 189                goto out;
 190
 191        ceph_decode_timespec(&validity, dp);
 192        dp += sizeof(struct ceph_timespec);
 193        new_expires = get_seconds() + validity.tv_sec;
 194        new_renew_after = new_expires - (validity.tv_sec / 4);
 195        dout(" expires=%lu renew_after=%lu\n", new_expires,
 196             new_renew_after);
 197
 198        /* ticket blob for service */
 199        ceph_decode_8_safe(p, end, is_enc, bad);
 200        if (is_enc) {
 201                /* encrypted */
 202                tp = *p + ceph_x_encrypt_offset();
 203                ret = ceph_x_decrypt(&th->session_key, p, end);
 204                if (ret < 0)
 205                        goto out;
 206                dout(" encrypted ticket, decrypted %d bytes\n", ret);
 207                ptp = &tp;
 208                tpend = tp + ret;
 209        } else {
 210                /* unencrypted */
 211                ptp = p;
 212                tpend = end;
 213        }
 214        ceph_decode_32_safe(ptp, tpend, dlen, bad);
 215        dout(" ticket blob is %d bytes\n", dlen);
 216        ceph_decode_need(ptp, tpend, 1 + sizeof(u64), bad);
 217        blob_struct_v = ceph_decode_8(ptp);
 218        if (blob_struct_v != 1)
 219                goto bad;
 220
 221        new_secret_id = ceph_decode_64(ptp);
 222        ret = ceph_decode_buffer(&new_ticket_blob, ptp, tpend);
 223        if (ret)
 224                goto out;
 225
 226        /* all is well, update our ticket */
 227        ceph_crypto_key_destroy(&th->session_key);
 228        if (th->ticket_blob)
 229                ceph_buffer_put(th->ticket_blob);
 230        th->session_key = new_session_key;
 231        th->ticket_blob = new_ticket_blob;
 232        th->secret_id = new_secret_id;
 233        th->expires = new_expires;
 234        th->renew_after = new_renew_after;
 235        th->have_key = true;
 236        dout(" got ticket service %d (%s) secret_id %lld len %d\n",
 237             type, ceph_entity_type_name(type), th->secret_id,
 238             (int)th->ticket_blob->vec.iov_len);
 239        xi->have_keys |= th->service;
 240        return 0;
 241
 242bad:
 243        ret = -EINVAL;
 244out:
 245        ceph_crypto_key_destroy(&new_session_key);
 246        return ret;
 247}
 248
 249static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
 250                                    struct ceph_crypto_key *secret,
 251                                    void *buf, void *end)
 252{
 253        void *p = buf;
 254        u8 reply_struct_v;
 255        u32 num;
 256        int ret;
 257
 258        ceph_decode_8_safe(&p, end, reply_struct_v, bad);
 259        if (reply_struct_v != 1)
 260                return -EINVAL;
 261
 262        ceph_decode_32_safe(&p, end, num, bad);
 263        dout("%d tickets\n", num);
 264
 265        while (num--) {
 266                ret = process_one_ticket(ac, secret, &p, end);
 267                if (ret)
 268                        return ret;
 269        }
 270
 271        return 0;
 272
 273bad:
 274        return -EINVAL;
 275}
 276
 277static void ceph_x_authorizer_cleanup(struct ceph_x_authorizer *au)
 278{
 279        ceph_crypto_key_destroy(&au->session_key);
 280        if (au->buf) {
 281                ceph_buffer_put(au->buf);
 282                au->buf = NULL;
 283        }
 284}
 285
 286static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
 287                                   struct ceph_x_ticket_handler *th,
 288                                   struct ceph_x_authorizer *au)
 289{
 290        int maxlen;
 291        struct ceph_x_authorize_a *msg_a;
 292        struct ceph_x_authorize_b *msg_b;
 293        void *p, *end;
 294        int ret;
 295        int ticket_blob_len =
 296                (th->ticket_blob ? th->ticket_blob->vec.iov_len : 0);
 297
 298        dout("build_authorizer for %s %p\n",
 299             ceph_entity_type_name(th->service), au);
 300
 301        ceph_crypto_key_destroy(&au->session_key);
 302        ret = ceph_crypto_key_clone(&au->session_key, &th->session_key);
 303        if (ret)
 304                goto out_au;
 305
 306        maxlen = sizeof(*msg_a) + ticket_blob_len +
 307                ceph_x_encrypt_buflen(sizeof(*msg_b));
 308        dout("  need len %d\n", maxlen);
 309        if (au->buf && au->buf->alloc_len < maxlen) {
 310                ceph_buffer_put(au->buf);
 311                au->buf = NULL;
 312        }
 313        if (!au->buf) {
 314                au->buf = ceph_buffer_new(maxlen, GFP_NOFS);
 315                if (!au->buf) {
 316                        ret = -ENOMEM;
 317                        goto out_au;
 318                }
 319        }
 320        au->service = th->service;
 321        au->secret_id = th->secret_id;
 322
 323        msg_a = au->buf->vec.iov_base;
 324        msg_a->struct_v = 1;
 325        msg_a->global_id = cpu_to_le64(ac->global_id);
 326        msg_a->service_id = cpu_to_le32(th->service);
 327        msg_a->ticket_blob.struct_v = 1;
 328        msg_a->ticket_blob.secret_id = cpu_to_le64(th->secret_id);
 329        msg_a->ticket_blob.blob_len = cpu_to_le32(ticket_blob_len);
 330        if (ticket_blob_len) {
 331                memcpy(msg_a->ticket_blob.blob, th->ticket_blob->vec.iov_base,
 332                       th->ticket_blob->vec.iov_len);
 333        }
 334        dout(" th %p secret_id %lld %lld\n", th, th->secret_id,
 335             le64_to_cpu(msg_a->ticket_blob.secret_id));
 336
 337        p = msg_a + 1;
 338        p += ticket_blob_len;
 339        end = au->buf->vec.iov_base + au->buf->vec.iov_len;
 340
 341        msg_b = p + ceph_x_encrypt_offset();
 342        msg_b->struct_v = 1;
 343        get_random_bytes(&au->nonce, sizeof(au->nonce));
 344        msg_b->nonce = cpu_to_le64(au->nonce);
 345        ret = ceph_x_encrypt(&au->session_key, p, end - p, sizeof(*msg_b));
 346        if (ret < 0)
 347                goto out_au;
 348
 349        p += ret;
 350        WARN_ON(p > end);
 351        au->buf->vec.iov_len = p - au->buf->vec.iov_base;
 352        dout(" built authorizer nonce %llx len %d\n", au->nonce,
 353             (int)au->buf->vec.iov_len);
 354        return 0;
 355
 356out_au:
 357        ceph_x_authorizer_cleanup(au);
 358        return ret;
 359}
 360
 361static int ceph_x_encode_ticket(struct ceph_x_ticket_handler *th,
 362                                void **p, void *end)
 363{
 364        ceph_decode_need(p, end, 1 + sizeof(u64), bad);
 365        ceph_encode_8(p, 1);
 366        ceph_encode_64(p, th->secret_id);
 367        if (th->ticket_blob) {
 368                const char *buf = th->ticket_blob->vec.iov_base;
 369                u32 len = th->ticket_blob->vec.iov_len;
 370
 371                ceph_encode_32_safe(p, end, len, bad);
 372                ceph_encode_copy_safe(p, end, buf, len, bad);
 373        } else {
 374                ceph_encode_32_safe(p, end, 0, bad);
 375        }
 376
 377        return 0;
 378bad:
 379        return -ERANGE;
 380}
 381
 382static bool need_key(struct ceph_x_ticket_handler *th)
 383{
 384        if (!th->have_key)
 385                return true;
 386
 387        return get_seconds() >= th->renew_after;
 388}
 389
 390static bool have_key(struct ceph_x_ticket_handler *th)
 391{
 392        if (th->have_key) {
 393                if (get_seconds() >= th->expires)
 394                        th->have_key = false;
 395        }
 396
 397        return th->have_key;
 398}
 399
 400static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed)
 401{
 402        int want = ac->want_keys;
 403        struct ceph_x_info *xi = ac->private;
 404        int service;
 405
 406        *pneed = ac->want_keys & ~(xi->have_keys);
 407
 408        for (service = 1; service <= want; service <<= 1) {
 409                struct ceph_x_ticket_handler *th;
 410
 411                if (!(ac->want_keys & service))
 412                        continue;
 413
 414                if (*pneed & service)
 415                        continue;
 416
 417                th = get_ticket_handler(ac, service);
 418                if (IS_ERR(th)) {
 419                        *pneed |= service;
 420                        continue;
 421                }
 422
 423                if (need_key(th))
 424                        *pneed |= service;
 425                if (!have_key(th))
 426                        xi->have_keys &= ~service;
 427        }
 428}
 429
 430static int ceph_x_build_request(struct ceph_auth_client *ac,
 431                                void *buf, void *end)
 432{
 433        struct ceph_x_info *xi = ac->private;
 434        int need;
 435        struct ceph_x_request_header *head = buf;
 436        int ret;
 437        struct ceph_x_ticket_handler *th =
 438                get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH);
 439
 440        if (IS_ERR(th))
 441                return PTR_ERR(th);
 442
 443        ceph_x_validate_tickets(ac, &need);
 444
 445        dout("build_request want %x have %x need %x\n",
 446             ac->want_keys, xi->have_keys, need);
 447
 448        if (need & CEPH_ENTITY_TYPE_AUTH) {
 449                struct ceph_x_authenticate *auth = (void *)(head + 1);
 450                void *p = auth + 1;
 451                void *enc_buf = xi->auth_authorizer.enc_buf;
 452                struct ceph_x_challenge_blob *blob = enc_buf +
 453                                                        ceph_x_encrypt_offset();
 454                u64 *u;
 455
 456                if (p > end)
 457                        return -ERANGE;
 458
 459                dout(" get_auth_session_key\n");
 460                head->op = cpu_to_le16(CEPHX_GET_AUTH_SESSION_KEY);
 461
 462                /* encrypt and hash */
 463                get_random_bytes(&auth->client_challenge, sizeof(u64));
 464                blob->client_challenge = auth->client_challenge;
 465                blob->server_challenge = cpu_to_le64(xi->server_challenge);
 466                ret = ceph_x_encrypt(&xi->secret, enc_buf, CEPHX_AU_ENC_BUF_LEN,
 467                                     sizeof(*blob));
 468                if (ret < 0)
 469                        return ret;
 470
 471                auth->struct_v = 1;
 472                auth->key = 0;
 473                for (u = (u64 *)enc_buf; u + 1 <= (u64 *)(enc_buf + ret); u++)
 474                        auth->key ^= *(__le64 *)u;
 475                dout(" server_challenge %llx client_challenge %llx key %llx\n",
 476                     xi->server_challenge, le64_to_cpu(auth->client_challenge),
 477                     le64_to_cpu(auth->key));
 478
 479                /* now encode the old ticket if exists */
 480                ret = ceph_x_encode_ticket(th, &p, end);
 481                if (ret < 0)
 482                        return ret;
 483
 484                return p - buf;
 485        }
 486
 487        if (need) {
 488                void *p = head + 1;
 489                struct ceph_x_service_ticket_request *req;
 490
 491                if (p > end)
 492                        return -ERANGE;
 493                head->op = cpu_to_le16(CEPHX_GET_PRINCIPAL_SESSION_KEY);
 494
 495                ret = ceph_x_build_authorizer(ac, th, &xi->auth_authorizer);
 496                if (ret)
 497                        return ret;
 498                ceph_encode_copy(&p, xi->auth_authorizer.buf->vec.iov_base,
 499                                 xi->auth_authorizer.buf->vec.iov_len);
 500
 501                req = p;
 502                req->keys = cpu_to_le32(need);
 503                p += sizeof(*req);
 504                return p - buf;
 505        }
 506
 507        return 0;
 508}
 509
 510static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result,
 511                               void *buf, void *end)
 512{
 513        struct ceph_x_info *xi = ac->private;
 514        struct ceph_x_reply_header *head = buf;
 515        struct ceph_x_ticket_handler *th;
 516        int len = end - buf;
 517        int op;
 518        int ret;
 519
 520        if (result)
 521                return result;  /* XXX hmm? */
 522
 523        if (xi->starting) {
 524                /* it's a hello */
 525                struct ceph_x_server_challenge *sc = buf;
 526
 527                if (len != sizeof(*sc))
 528                        return -EINVAL;
 529                xi->server_challenge = le64_to_cpu(sc->server_challenge);
 530                dout("handle_reply got server challenge %llx\n",
 531                     xi->server_challenge);
 532                xi->starting = false;
 533                xi->have_keys &= ~CEPH_ENTITY_TYPE_AUTH;
 534                return -EAGAIN;
 535        }
 536
 537        op = le16_to_cpu(head->op);
 538        result = le32_to_cpu(head->result);
 539        dout("handle_reply op %d result %d\n", op, result);
 540        switch (op) {
 541        case CEPHX_GET_AUTH_SESSION_KEY:
 542                /* verify auth key */
 543                ret = ceph_x_proc_ticket_reply(ac, &xi->secret,
 544                                               buf + sizeof(*head), end);
 545                break;
 546
 547        case CEPHX_GET_PRINCIPAL_SESSION_KEY:
 548                th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH);
 549                if (IS_ERR(th))
 550                        return PTR_ERR(th);
 551                ret = ceph_x_proc_ticket_reply(ac, &th->session_key,
 552                                               buf + sizeof(*head), end);
 553                break;
 554
 555        default:
 556                return -EINVAL;
 557        }
 558        if (ret)
 559                return ret;
 560        if (ac->want_keys == xi->have_keys)
 561                return 0;
 562        return -EAGAIN;
 563}
 564
 565static void ceph_x_destroy_authorizer(struct ceph_authorizer *a)
 566{
 567        struct ceph_x_authorizer *au = (void *)a;
 568
 569        ceph_x_authorizer_cleanup(au);
 570        kfree(au);
 571}
 572
 573static int ceph_x_create_authorizer(
 574        struct ceph_auth_client *ac, int peer_type,
 575        struct ceph_auth_handshake *auth)
 576{
 577        struct ceph_x_authorizer *au;
 578        struct ceph_x_ticket_handler *th;
 579        int ret;
 580
 581        th = get_ticket_handler(ac, peer_type);
 582        if (IS_ERR(th))
 583                return PTR_ERR(th);
 584
 585        au = kzalloc(sizeof(*au), GFP_NOFS);
 586        if (!au)
 587                return -ENOMEM;
 588
 589        au->base.destroy = ceph_x_destroy_authorizer;
 590
 591        ret = ceph_x_build_authorizer(ac, th, au);
 592        if (ret) {
 593                kfree(au);
 594                return ret;
 595        }
 596
 597        auth->authorizer = (struct ceph_authorizer *) au;
 598        auth->authorizer_buf = au->buf->vec.iov_base;
 599        auth->authorizer_buf_len = au->buf->vec.iov_len;
 600        auth->authorizer_reply_buf = au->enc_buf;
 601        auth->authorizer_reply_buf_len = CEPHX_AU_ENC_BUF_LEN;
 602        auth->sign_message = ac->ops->sign_message;
 603        auth->check_message_signature = ac->ops->check_message_signature;
 604
 605        return 0;
 606}
 607
 608static int ceph_x_update_authorizer(
 609        struct ceph_auth_client *ac, int peer_type,
 610        struct ceph_auth_handshake *auth)
 611{
 612        struct ceph_x_authorizer *au;
 613        struct ceph_x_ticket_handler *th;
 614
 615        th = get_ticket_handler(ac, peer_type);
 616        if (IS_ERR(th))
 617                return PTR_ERR(th);
 618
 619        au = (struct ceph_x_authorizer *)auth->authorizer;
 620        if (au->secret_id < th->secret_id) {
 621                dout("ceph_x_update_authorizer service %u secret %llu < %llu\n",
 622                     au->service, au->secret_id, th->secret_id);
 623                return ceph_x_build_authorizer(ac, th, au);
 624        }
 625        return 0;
 626}
 627
 628static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac,
 629                                          struct ceph_authorizer *a)
 630{
 631        struct ceph_x_authorizer *au = (void *)a;
 632        void *p = au->enc_buf;
 633        struct ceph_x_authorize_reply *reply = p + ceph_x_encrypt_offset();
 634        int ret;
 635
 636        ret = ceph_x_decrypt(&au->session_key, &p, p + CEPHX_AU_ENC_BUF_LEN);
 637        if (ret < 0)
 638                return ret;
 639        if (ret != sizeof(*reply))
 640                return -EPERM;
 641
 642        if (au->nonce + 1 != le64_to_cpu(reply->nonce_plus_one))
 643                ret = -EPERM;
 644        else
 645                ret = 0;
 646        dout("verify_authorizer_reply nonce %llx got %llx ret %d\n",
 647             au->nonce, le64_to_cpu(reply->nonce_plus_one), ret);
 648        return ret;
 649}
 650
 651static void ceph_x_reset(struct ceph_auth_client *ac)
 652{
 653        struct ceph_x_info *xi = ac->private;
 654
 655        dout("reset\n");
 656        xi->starting = true;
 657        xi->server_challenge = 0;
 658}
 659
 660static void ceph_x_destroy(struct ceph_auth_client *ac)
 661{
 662        struct ceph_x_info *xi = ac->private;
 663        struct rb_node *p;
 664
 665        dout("ceph_x_destroy %p\n", ac);
 666        ceph_crypto_key_destroy(&xi->secret);
 667
 668        while ((p = rb_first(&xi->ticket_handlers)) != NULL) {
 669                struct ceph_x_ticket_handler *th =
 670                        rb_entry(p, struct ceph_x_ticket_handler, node);
 671                remove_ticket_handler(ac, th);
 672        }
 673
 674        ceph_x_authorizer_cleanup(&xi->auth_authorizer);
 675
 676        kfree(ac->private);
 677        ac->private = NULL;
 678}
 679
 680static void invalidate_ticket(struct ceph_auth_client *ac, int peer_type)
 681{
 682        struct ceph_x_ticket_handler *th;
 683
 684        th = get_ticket_handler(ac, peer_type);
 685        if (!IS_ERR(th))
 686                th->have_key = false;
 687}
 688
 689static void ceph_x_invalidate_authorizer(struct ceph_auth_client *ac,
 690                                         int peer_type)
 691{
 692        /*
 693         * We are to invalidate a service ticket in the hopes of
 694         * getting a new, hopefully more valid, one.  But, we won't get
 695         * it unless our AUTH ticket is good, so invalidate AUTH ticket
 696         * as well, just in case.
 697         */
 698        invalidate_ticket(ac, peer_type);
 699        invalidate_ticket(ac, CEPH_ENTITY_TYPE_AUTH);
 700}
 701
 702static int calc_signature(struct ceph_x_authorizer *au, struct ceph_msg *msg,
 703                          __le64 *psig)
 704{
 705        void *enc_buf = au->enc_buf;
 706        struct {
 707                __le32 len;
 708                __le32 header_crc;
 709                __le32 front_crc;
 710                __le32 middle_crc;
 711                __le32 data_crc;
 712        } __packed *sigblock = enc_buf + ceph_x_encrypt_offset();
 713        int ret;
 714
 715        sigblock->len = cpu_to_le32(4*sizeof(u32));
 716        sigblock->header_crc = msg->hdr.crc;
 717        sigblock->front_crc = msg->footer.front_crc;
 718        sigblock->middle_crc = msg->footer.middle_crc;
 719        sigblock->data_crc =  msg->footer.data_crc;
 720        ret = ceph_x_encrypt(&au->session_key, enc_buf, CEPHX_AU_ENC_BUF_LEN,
 721                             sizeof(*sigblock));
 722        if (ret < 0)
 723                return ret;
 724
 725        *psig = *(__le64 *)(enc_buf + sizeof(u32));
 726        return 0;
 727}
 728
 729static int ceph_x_sign_message(struct ceph_auth_handshake *auth,
 730                               struct ceph_msg *msg)
 731{
 732        __le64 sig;
 733        int ret;
 734
 735        if (ceph_test_opt(from_msgr(msg->con->msgr), NOMSGSIGN))
 736                return 0;
 737
 738        ret = calc_signature((struct ceph_x_authorizer *)auth->authorizer,
 739                             msg, &sig);
 740        if (ret)
 741                return ret;
 742
 743        msg->footer.sig = sig;
 744        msg->footer.flags |= CEPH_MSG_FOOTER_SIGNED;
 745        return 0;
 746}
 747
 748static int ceph_x_check_message_signature(struct ceph_auth_handshake *auth,
 749                                          struct ceph_msg *msg)
 750{
 751        __le64 sig_check;
 752        int ret;
 753
 754        if (ceph_test_opt(from_msgr(msg->con->msgr), NOMSGSIGN))
 755                return 0;
 756
 757        ret = calc_signature((struct ceph_x_authorizer *)auth->authorizer,
 758                             msg, &sig_check);
 759        if (ret)
 760                return ret;
 761        if (sig_check == msg->footer.sig)
 762                return 0;
 763        if (msg->footer.flags & CEPH_MSG_FOOTER_SIGNED)
 764                dout("ceph_x_check_message_signature %p has signature %llx "
 765                     "expect %llx\n", msg, msg->footer.sig, sig_check);
 766        else
 767                dout("ceph_x_check_message_signature %p sender did not set "
 768                     "CEPH_MSG_FOOTER_SIGNED\n", msg);
 769        return -EBADMSG;
 770}
 771
 772static const struct ceph_auth_client_ops ceph_x_ops = {
 773        .name = "x",
 774        .is_authenticated = ceph_x_is_authenticated,
 775        .should_authenticate = ceph_x_should_authenticate,
 776        .build_request = ceph_x_build_request,
 777        .handle_reply = ceph_x_handle_reply,
 778        .create_authorizer = ceph_x_create_authorizer,
 779        .update_authorizer = ceph_x_update_authorizer,
 780        .verify_authorizer_reply = ceph_x_verify_authorizer_reply,
 781        .invalidate_authorizer = ceph_x_invalidate_authorizer,
 782        .reset =  ceph_x_reset,
 783        .destroy = ceph_x_destroy,
 784        .sign_message = ceph_x_sign_message,
 785        .check_message_signature = ceph_x_check_message_signature,
 786};
 787
 788
 789int ceph_x_init(struct ceph_auth_client *ac)
 790{
 791        struct ceph_x_info *xi;
 792        int ret;
 793
 794        dout("ceph_x_init %p\n", ac);
 795        ret = -ENOMEM;
 796        xi = kzalloc(sizeof(*xi), GFP_NOFS);
 797        if (!xi)
 798                goto out;
 799
 800        ret = -EINVAL;
 801        if (!ac->key) {
 802                pr_err("no secret set (for auth_x protocol)\n");
 803                goto out_nomem;
 804        }
 805
 806        ret = ceph_crypto_key_clone(&xi->secret, ac->key);
 807        if (ret < 0) {
 808                pr_err("cannot clone key: %d\n", ret);
 809                goto out_nomem;
 810        }
 811
 812        xi->starting = true;
 813        xi->ticket_handlers = RB_ROOT;
 814
 815        ac->protocol = CEPH_AUTH_CEPHX;
 816        ac->private = xi;
 817        ac->ops = &ceph_x_ops;
 818        return 0;
 819
 820out_nomem:
 821        kfree(xi);
 822out:
 823        return ret;
 824}
 825
 826
 827