linux/net/sunrpc/auth_gss/gss_krb5_mech.c
<<
>>
Prefs
   1/*
   2 *  linux/net/sunrpc/gss_krb5_mech.c
   3 *
   4 *  Copyright (c) 2001 The Regents of the University of Michigan.
   5 *  All rights reserved.
   6 *
   7 *  Andy Adamson <andros@umich.edu>
   8 *  J. Bruce Fields <bfields@umich.edu>
   9 *
  10 *  Redistribution and use in source and binary forms, with or without
  11 *  modification, are permitted provided that the following conditions
  12 *  are met:
  13 *
  14 *  1. Redistributions of source code must retain the above copyright
  15 *     notice, this list of conditions and the following disclaimer.
  16 *  2. Redistributions in binary form must reproduce the above copyright
  17 *     notice, this list of conditions and the following disclaimer in the
  18 *     documentation and/or other materials provided with the distribution.
  19 *  3. Neither the name of the University nor the names of its
  20 *     contributors may be used to endorse or promote products derived
  21 *     from this software without specific prior written permission.
  22 *
  23 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  24 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  25 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  28 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  30 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  31 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  32 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  33 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34 *
  35 */
  36
  37#include <linux/err.h>
  38#include <linux/module.h>
  39#include <linux/init.h>
  40#include <linux/types.h>
  41#include <linux/slab.h>
  42#include <linux/sunrpc/auth.h>
  43#include <linux/sunrpc/gss_krb5.h>
  44#include <linux/sunrpc/xdr.h>
  45#include <linux/crypto.h>
  46
  47#ifdef RPC_DEBUG
  48# define RPCDBG_FACILITY        RPCDBG_AUTH
  49#endif
  50
  51static const void *
  52simple_get_bytes(const void *p, const void *end, void *res, int len)
  53{
  54        const void *q = (const void *)((const char *)p + len);
  55        if (unlikely(q > end || q < p))
  56                return ERR_PTR(-EFAULT);
  57        memcpy(res, p, len);
  58        return q;
  59}
  60
  61static const void *
  62simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
  63{
  64        const void *q;
  65        unsigned int len;
  66
  67        p = simple_get_bytes(p, end, &len, sizeof(len));
  68        if (IS_ERR(p))
  69                return p;
  70        q = (const void *)((const char *)p + len);
  71        if (unlikely(q > end || q < p))
  72                return ERR_PTR(-EFAULT);
  73        res->data = kmemdup(p, len, GFP_NOFS);
  74        if (unlikely(res->data == NULL))
  75                return ERR_PTR(-ENOMEM);
  76        res->len = len;
  77        return q;
  78}
  79
  80static inline const void *
  81get_key(const void *p, const void *end, struct crypto_blkcipher **res)
  82{
  83        struct xdr_netobj       key;
  84        int                     alg;
  85        char                    *alg_name;
  86
  87        p = simple_get_bytes(p, end, &alg, sizeof(alg));
  88        if (IS_ERR(p))
  89                goto out_err;
  90        p = simple_get_netobj(p, end, &key);
  91        if (IS_ERR(p))
  92                goto out_err;
  93
  94        switch (alg) {
  95                case ENCTYPE_DES_CBC_RAW:
  96                        alg_name = "cbc(des)";
  97                        break;
  98                default:
  99                        printk("gss_kerberos_mech: unsupported algorithm %d\n", alg);
 100                        goto out_err_free_key;
 101        }
 102        *res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC);
 103        if (IS_ERR(*res)) {
 104                printk("gss_kerberos_mech: unable to initialize crypto algorithm %s\n", alg_name);
 105                *res = NULL;
 106                goto out_err_free_key;
 107        }
 108        if (crypto_blkcipher_setkey(*res, key.data, key.len)) {
 109                printk("gss_kerberos_mech: error setting key for crypto algorithm %s\n", alg_name);
 110                goto out_err_free_tfm;
 111        }
 112
 113        kfree(key.data);
 114        return p;
 115
 116out_err_free_tfm:
 117        crypto_free_blkcipher(*res);
 118out_err_free_key:
 119        kfree(key.data);
 120        p = ERR_PTR(-EINVAL);
 121out_err:
 122        return p;
 123}
 124
 125static int
 126gss_import_sec_context_kerberos(const void *p,
 127                                size_t len,
 128                                struct gss_ctx *ctx_id)
 129{
 130        const void *end = (const void *)((const char *)p + len);
 131        struct  krb5_ctx *ctx;
 132        int tmp;
 133
 134        if (!(ctx = kzalloc(sizeof(*ctx), GFP_NOFS)))
 135                goto out_err;
 136
 137        p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate));
 138        if (IS_ERR(p))
 139                goto out_err_free_ctx;
 140        /* The downcall format was designed before we completely understood
 141         * the uses of the context fields; so it includes some stuff we
 142         * just give some minimal sanity-checking, and some we ignore
 143         * completely (like the next twenty bytes): */
 144        if (unlikely(p + 20 > end || p + 20 < p))
 145                goto out_err_free_ctx;
 146        p += 20;
 147        p = simple_get_bytes(p, end, &tmp, sizeof(tmp));
 148        if (IS_ERR(p))
 149                goto out_err_free_ctx;
 150        if (tmp != SGN_ALG_DES_MAC_MD5) {
 151                p = ERR_PTR(-ENOSYS);
 152                goto out_err_free_ctx;
 153        }
 154        p = simple_get_bytes(p, end, &tmp, sizeof(tmp));
 155        if (IS_ERR(p))
 156                goto out_err_free_ctx;
 157        if (tmp != SEAL_ALG_DES) {
 158                p = ERR_PTR(-ENOSYS);
 159                goto out_err_free_ctx;
 160        }
 161        p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
 162        if (IS_ERR(p))
 163                goto out_err_free_ctx;
 164        p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send));
 165        if (IS_ERR(p))
 166                goto out_err_free_ctx;
 167        p = simple_get_netobj(p, end, &ctx->mech_used);
 168        if (IS_ERR(p))
 169                goto out_err_free_ctx;
 170        p = get_key(p, end, &ctx->enc);
 171        if (IS_ERR(p))
 172                goto out_err_free_mech;
 173        p = get_key(p, end, &ctx->seq);
 174        if (IS_ERR(p))
 175                goto out_err_free_key1;
 176        if (p != end) {
 177                p = ERR_PTR(-EFAULT);
 178                goto out_err_free_key2;
 179        }
 180
 181        ctx_id->internal_ctx_id = ctx;
 182
 183        dprintk("RPC:       Successfully imported new context.\n");
 184        return 0;
 185
 186out_err_free_key2:
 187        crypto_free_blkcipher(ctx->seq);
 188out_err_free_key1:
 189        crypto_free_blkcipher(ctx->enc);
 190out_err_free_mech:
 191        kfree(ctx->mech_used.data);
 192out_err_free_ctx:
 193        kfree(ctx);
 194out_err:
 195        return PTR_ERR(p);
 196}
 197
 198static void
 199gss_delete_sec_context_kerberos(void *internal_ctx) {
 200        struct krb5_ctx *kctx = internal_ctx;
 201
 202        crypto_free_blkcipher(kctx->seq);
 203        crypto_free_blkcipher(kctx->enc);
 204        kfree(kctx->mech_used.data);
 205        kfree(kctx);
 206}
 207
 208static const struct gss_api_ops gss_kerberos_ops = {
 209        .gss_import_sec_context = gss_import_sec_context_kerberos,
 210        .gss_get_mic            = gss_get_mic_kerberos,
 211        .gss_verify_mic         = gss_verify_mic_kerberos,
 212        .gss_wrap               = gss_wrap_kerberos,
 213        .gss_unwrap             = gss_unwrap_kerberos,
 214        .gss_delete_sec_context = gss_delete_sec_context_kerberos,
 215};
 216
 217static struct pf_desc gss_kerberos_pfs[] = {
 218        [0] = {
 219                .pseudoflavor = RPC_AUTH_GSS_KRB5,
 220                .service = RPC_GSS_SVC_NONE,
 221                .name = "krb5",
 222        },
 223        [1] = {
 224                .pseudoflavor = RPC_AUTH_GSS_KRB5I,
 225                .service = RPC_GSS_SVC_INTEGRITY,
 226                .name = "krb5i",
 227        },
 228        [2] = {
 229                .pseudoflavor = RPC_AUTH_GSS_KRB5P,
 230                .service = RPC_GSS_SVC_PRIVACY,
 231                .name = "krb5p",
 232        },
 233};
 234
 235static struct gss_api_mech gss_kerberos_mech = {
 236        .gm_name        = "krb5",
 237        .gm_owner       = THIS_MODULE,
 238        .gm_oid         = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"},
 239        .gm_ops         = &gss_kerberos_ops,
 240        .gm_pf_num      = ARRAY_SIZE(gss_kerberos_pfs),
 241        .gm_pfs         = gss_kerberos_pfs,
 242};
 243
 244static int __init init_kerberos_module(void)
 245{
 246        int status;
 247
 248        status = gss_mech_register(&gss_kerberos_mech);
 249        if (status)
 250                printk("Failed to register kerberos gss mechanism!\n");
 251        return status;
 252}
 253
 254static void __exit cleanup_kerberos_module(void)
 255{
 256        gss_mech_unregister(&gss_kerberos_mech);
 257}
 258
 259MODULE_LICENSE("GPL");
 260module_init(init_kerberos_module);
 261module_exit(cleanup_kerberos_module);
 262
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.