X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsunrpc%2Fauth_gss%2Fgss_krb5_mech.c;h=05d4bee86fc06d32c0ab559a936bfff92b8623ae;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=0082fb5c999a1c035262dd51f4019396681f2945;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 0082fb5c9..05d4bee86 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -34,12 +34,12 @@ * */ +#include #include #include #include #include #include -#include #include #include #include @@ -48,177 +48,164 @@ # define RPCDBG_FACILITY RPCDBG_AUTH #endif -struct xdr_netobj gss_mech_krb5_oid = - {9, "\052\206\110\206\367\022\001\002\002"}; - -static inline int -get_bytes(char **ptr, const char *end, void *res, int len) +static const void * +simple_get_bytes(const void *p, const void *end, void *res, int len) { - char *p, *q; - p = *ptr; - q = p + len; - if (q > end || q < p) - return -1; + const void *q = (const void *)((const char *)p + len); + if (unlikely(q > end || q < p)) + return ERR_PTR(-EFAULT); memcpy(res, p, len); - *ptr = q; - return 0; + return q; } -static inline int -get_netobj(char **ptr, const char *end, struct xdr_netobj *res) +static const void * +simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) { - char *p, *q; - p = *ptr; - if (get_bytes(&p, end, &res->len, sizeof(res->len))) - return -1; - q = p + res->len; - if (q > end || q < p) - return -1; - if (!(res->data = kmalloc(res->len, GFP_KERNEL))) - return -1; - memcpy(res->data, p, res->len); - *ptr = q; - return 0; + const void *q; + unsigned int len; + + p = simple_get_bytes(p, end, &len, sizeof(len)); + if (IS_ERR(p)) + return p; + q = (const void *)((const char *)p + len); + if (unlikely(q > end || q < p)) + return ERR_PTR(-EFAULT); + res->data = kmemdup(p, len, GFP_KERNEL); + if (unlikely(res->data == NULL)) + return ERR_PTR(-ENOMEM); + res->len = len; + return q; } -static inline int -get_key(char **p, char *end, struct crypto_tfm **res) +static inline const void * +get_key(const void *p, const void *end, struct crypto_blkcipher **res) { struct xdr_netobj key; - int alg, alg_mode; + int alg; char *alg_name; - if (get_bytes(p, end, &alg, sizeof(alg))) + p = simple_get_bytes(p, end, &alg, sizeof(alg)); + if (IS_ERR(p)) goto out_err; - if ((get_netobj(p, end, &key))) + p = simple_get_netobj(p, end, &key); + if (IS_ERR(p)) goto out_err; switch (alg) { case ENCTYPE_DES_CBC_RAW: - alg_name = "des"; - alg_mode = CRYPTO_TFM_MODE_CBC; + alg_name = "cbc(des)"; break; default: - dprintk("RPC: get_key: unsupported algorithm %d\n", alg); + printk("gss_kerberos_mech: unsupported algorithm %d\n", alg); goto out_err_free_key; } - if (!(*res = crypto_alloc_tfm(alg_name, alg_mode))) + *res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(*res)) { + printk("gss_kerberos_mech: unable to initialize crypto algorithm %s\n", alg_name); + *res = NULL; goto out_err_free_key; - if (crypto_cipher_setkey(*res, key.data, key.len)) + } + if (crypto_blkcipher_setkey(*res, key.data, key.len)) { + printk("gss_kerberos_mech: error setting key for crypto algorithm %s\n", alg_name); goto out_err_free_tfm; + } kfree(key.data); - return 0; + return p; out_err_free_tfm: - crypto_free_tfm(*res); + crypto_free_blkcipher(*res); out_err_free_key: kfree(key.data); + p = ERR_PTR(-EINVAL); out_err: - return -1; + return p; } -static u32 -gss_import_sec_context_kerberos(struct xdr_netobj *inbuf, +static int +gss_import_sec_context_kerberos(const void *p, + size_t len, struct gss_ctx *ctx_id) { - char *p = inbuf->data; - char *end = inbuf->data + inbuf->len; + const void *end = (const void *)((const char *)p + len); struct krb5_ctx *ctx; + int tmp; - if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL))) + if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL))) goto out_err; - memset(ctx, 0, sizeof(*ctx)); - if (get_bytes(&p, end, &ctx->initiate, sizeof(ctx->initiate))) + p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); + if (IS_ERR(p)) + goto out_err_free_ctx; + /* The downcall format was designed before we completely understood + * the uses of the context fields; so it includes some stuff we + * just give some minimal sanity-checking, and some we ignore + * completely (like the next twenty bytes): */ + if (unlikely(p + 20 > end || p + 20 < p)) goto out_err_free_ctx; - if (get_bytes(&p, end, &ctx->seed_init, sizeof(ctx->seed_init))) + p += 20; + p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_bytes(&p, end, ctx->seed, sizeof(ctx->seed))) + if (tmp != SGN_ALG_DES_MAC_MD5) goto out_err_free_ctx; - if (get_bytes(&p, end, &ctx->signalg, sizeof(ctx->signalg))) + p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_bytes(&p, end, &ctx->sealalg, sizeof(ctx->sealalg))) + if (tmp != SEAL_ALG_DES) goto out_err_free_ctx; - if (get_bytes(&p, end, &ctx->endtime, sizeof(ctx->endtime))) + p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_bytes(&p, end, &ctx->seq_send, sizeof(ctx->seq_send))) + p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send)); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_netobj(&p, end, &ctx->mech_used)) + p = simple_get_netobj(p, end, &ctx->mech_used); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_key(&p, end, &ctx->enc)) + p = get_key(p, end, &ctx->enc); + if (IS_ERR(p)) goto out_err_free_mech; - if (get_key(&p, end, &ctx->seq)) + p = get_key(p, end, &ctx->seq); + if (IS_ERR(p)) goto out_err_free_key1; - if (p != end) + if (p != end) { + p = ERR_PTR(-EFAULT); goto out_err_free_key2; + } ctx_id->internal_ctx_id = ctx; - dprintk("RPC: Succesfully imported new context.\n"); + dprintk("RPC: Successfully imported new context.\n"); return 0; out_err_free_key2: - crypto_free_tfm(ctx->seq); + crypto_free_blkcipher(ctx->seq); out_err_free_key1: - crypto_free_tfm(ctx->enc); + crypto_free_blkcipher(ctx->enc); out_err_free_mech: kfree(ctx->mech_used.data); out_err_free_ctx: kfree(ctx); out_err: - return GSS_S_FAILURE; + return PTR_ERR(p); } static void gss_delete_sec_context_kerberos(void *internal_ctx) { struct krb5_ctx *kctx = internal_ctx; - if (kctx->seq) - crypto_free_tfm(kctx->seq); - if (kctx->enc) - crypto_free_tfm(kctx->enc); - if (kctx->mech_used.data) - kfree(kctx->mech_used.data); + crypto_free_blkcipher(kctx->seq); + crypto_free_blkcipher(kctx->enc); + kfree(kctx->mech_used.data); kfree(kctx); } -static u32 -gss_verify_mic_kerberos(struct gss_ctx *ctx, - struct xdr_buf *message, - struct xdr_netobj *mic_token, - u32 *qstate) { - u32 maj_stat = 0; - int qop_state; - struct krb5_ctx *kctx = ctx->internal_ctx_id; - - maj_stat = krb5_read_token(kctx, mic_token, message, &qop_state, - KG_TOK_MIC_MSG); - if (!maj_stat && qop_state) - *qstate = qop_state; - - dprintk("RPC: gss_verify_mic_kerberos returning %d\n", maj_stat); - return maj_stat; -} - -static u32 -gss_get_mic_kerberos(struct gss_ctx *ctx, - u32 qop, - struct xdr_buf *message, - struct xdr_netobj *mic_token) { - u32 err = 0; - struct krb5_ctx *kctx = ctx->internal_ctx_id; - - err = krb5_make_token(kctx, qop, message, mic_token, KG_TOK_MIC_MSG); - - dprintk("RPC: gss_get_mic_kerberos returning %d\n",err); - - return err; -} - static struct gss_api_ops gss_kerberos_ops = { .gss_import_sec_context = gss_import_sec_context_kerberos, .gss_get_mic = gss_get_mic_kerberos, .gss_verify_mic = gss_verify_mic_kerberos, + .gss_wrap = gss_wrap_kerberos, + .gss_unwrap = gss_unwrap_kerberos, .gss_delete_sec_context = gss_delete_sec_context_kerberos, }; @@ -233,6 +220,11 @@ static struct pf_desc gss_kerberos_pfs[] = { .service = RPC_GSS_SVC_INTEGRITY, .name = "krb5i", }, + [2] = { + .pseudoflavor = RPC_AUTH_GSS_KRB5P, + .service = RPC_GSS_SVC_PRIVACY, + .name = "krb5p", + }, }; static struct gss_api_mech gss_kerberos_mech = {