static inline const void * get_key(const void *p, const void *end, struct crypto_blkcipher **res) { struct xdr_netobj key; int alg; char *alg_name; p = simple_get_bytes(p, end, &alg, sizeof(alg)); if (IS_ERR(p)) goto out_err; p = simple_get_netobj(p, end, &key); if (IS_ERR(p)) goto out_err; switch (alg) { case ENCTYPE_DES_CBC_RAW: alg_name = "cbc(des)"; break; default: printk("gss_kerberos_mech: unsupported algorithm %d\n", alg); goto out_err_free_key; } *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_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 p; out_err_free_tfm: crypto_free_blkcipher(*res); out_err_free_key: kfree(key.data); p = ERR_PTR(-EINVAL); out_err: return p; }
static const void * simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) { 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 = kmalloc(len, GFP_KERNEL); if (unlikely(res->data == NULL)) return ERR_PTR(-ENOMEM); memcpy(res->data, p, len); res->len = len; return q; }
static int gss_import_sec_context_kerberos(const void *p, size_t len, struct gss_ctx *ctx_id) { const void *end = (const void *)((const char *)p + len); struct krb5_ctx *ctx; int tmp; if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL))) goto out_err; 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; p += 20; p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); if (IS_ERR(p)) goto out_err_free_ctx; if (tmp != SGN_ALG_DES_MAC_MD5) goto out_err_free_ctx; p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); if (IS_ERR(p)) goto out_err_free_ctx; if (tmp != SEAL_ALG_DES) goto out_err_free_ctx; p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); if (IS_ERR(p)) goto out_err_free_ctx; p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send)); if (IS_ERR(p)) goto out_err_free_ctx; p = simple_get_netobj(p, end, &ctx->mech_used); if (IS_ERR(p)) goto out_err_free_ctx; p = get_key(p, end, &ctx->enc); if (IS_ERR(p)) goto out_err_free_mech; p = get_key(p, end, &ctx->seq); if (IS_ERR(p)) goto out_err_free_key1; if (p != end) { p = ERR_PTR(-EFAULT); goto out_err_free_key2; } ctx_id->internal_ctx_id = ctx; dprintk("RPC: Successfully imported new context.\n"); return 0; out_err_free_key2: crypto_free_blkcipher(ctx->seq); out_err_free_key1: crypto_free_blkcipher(ctx->enc); out_err_free_mech: kfree(ctx->mech_used.data); out_err_free_ctx: kfree(ctx); out_err: return PTR_ERR(p); }
static int gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx) { int tmp; p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); if (IS_ERR(p)) goto out_err; /* Old format supports only DES! Any other enctype uses new format */ ctx->enctype = ENCTYPE_DES_CBC_RAW; ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); if (ctx->gk5e == NULL) { p = ERR_PTR(-EINVAL); goto out_err; } /* 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)) { p = ERR_PTR(-EFAULT); goto out_err; } p += 20; p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); if (IS_ERR(p)) goto out_err; if (tmp != SGN_ALG_DES_MAC_MD5) { p = ERR_PTR(-ENOSYS); goto out_err; } p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); if (IS_ERR(p)) goto out_err; if (tmp != SEAL_ALG_DES) { p = ERR_PTR(-ENOSYS); goto out_err; } p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); if (IS_ERR(p)) goto out_err; p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send)); if (IS_ERR(p)) goto out_err; p = simple_get_netobj(p, end, &ctx->mech_used); if (IS_ERR(p)) goto out_err; p = get_key(p, end, ctx, &ctx->enc); if (IS_ERR(p)) goto out_err_free_mech; p = get_key(p, end, ctx, &ctx->seq); if (IS_ERR(p)) goto out_err_free_key1; if (p != end) { p = ERR_PTR(-EFAULT); goto out_err_free_key2; } return 0; out_err_free_key2: crypto_free_blkcipher(ctx->seq); out_err_free_key1: crypto_free_blkcipher(ctx->enc); out_err_free_mech: kfree(ctx->mech_used.data); out_err: return PTR_ERR(p); }
static const void * gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct gss_api_mech *gm) { const void *q; unsigned int seclen; unsigned int timeout; unsigned long now = jiffies; u32 window_size; int ret; /* First unsigned int gives the remaining lifetime in seconds of the * credential - e.g. the remaining TGT lifetime for Kerberos or * the -t value passed to GSSD. */ p = simple_get_bytes(p, end, &timeout, sizeof(timeout)); if (IS_ERR(p)) goto err; if (timeout == 0) timeout = GSSD_MIN_TIMEOUT; ctx->gc_expiry = now + ((unsigned long)timeout * HZ); /* Sequence number window. Determines the maximum number of * simultaneous requests */ p = simple_get_bytes(p, end, &window_size, sizeof(window_size)); if (IS_ERR(p)) goto err; ctx->gc_win = window_size; /* gssd signals an error by passing ctx->gc_win = 0: */ if (ctx->gc_win == 0) { /* * in which case, p points to an error code. Anything other * than -EKEYEXPIRED gets converted to -EACCES. */ p = simple_get_bytes(p, end, &ret, sizeof(ret)); if (!IS_ERR(p)) p = (ret == -EKEYEXPIRED) ? ERR_PTR(-EKEYEXPIRED) : ERR_PTR(-EACCES); goto err; } /* copy the opaque wire context */ p = simple_get_netobj(p, end, &ctx->gc_wire_ctx); if (IS_ERR(p)) goto err; /* import the opaque security context */ p = simple_get_bytes(p, end, &seclen, sizeof(seclen)); if (IS_ERR(p)) goto err; q = (const void *)((const char *)p + seclen); if (unlikely(q > end || q < p)) { p = ERR_PTR(-EFAULT); goto err; } ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx, NULL, GFP_NOFS); if (ret < 0) { p = ERR_PTR(ret); goto err; } /* is there any trailing data? */ if (q == end) { p = q; goto done; } /* pull in acceptor name (if there is one) */ p = simple_get_netobj(q, end, &ctx->gc_acceptor); if (IS_ERR(p)) goto err; done: dprintk("RPC: %s Success. gc_expiry %lu now %lu timeout %u acceptor %.*s\n", __fun
static int gss_import_sec_context_kerberos(const void *p, size_t len, struct gss_ctx *ctx_id) { const void *end = (const void *)((const char *)p + len); struct krb5_ctx *ctx; if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL))) goto out_err; p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); if (IS_ERR(p)) goto out_err_free_ctx; p = simple_get_bytes(p, end, &ctx->seed_init, sizeof(ctx->seed_init)); if (IS_ERR(p)) goto out_err_free_ctx; p = simple_get_bytes(p, end, ctx->seed, sizeof(ctx->seed)); if (IS_ERR(p)) goto out_err_free_ctx; p = simple_get_bytes(p, end, &ctx->signalg, sizeof(ctx->signalg)); if (IS_ERR(p)) goto out_err_free_ctx; p = simple_get_bytes(p, end, &ctx->sealalg, sizeof(ctx->sealalg)); if (IS_ERR(p)) goto out_err_free_ctx; p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); if (IS_ERR(p)) goto out_err_free_ctx; p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send)); if (IS_ERR(p)) goto out_err_free_ctx; p = simple_get_netobj(p, end, &ctx->mech_used); if (IS_ERR(p)) goto out_err_free_ctx; p = get_key(p, end, &ctx->enc); if (IS_ERR(p)) goto out_err_free_mech; p = get_key(p, end, &ctx->seq); if (IS_ERR(p)) goto out_err_free_key1; if (p != end) { p = ERR_PTR(-EFAULT); goto out_err_free_key2; } ctx_id->internal_ctx_id = ctx; dprintk("RPC: Successfully imported new context.\n"); return 0; out_err_free_key2: crypto_free_tfm(ctx->seq); out_err_free_key1: crypto_free_tfm(ctx->enc); out_err_free_mech: kfree(ctx->mech_used.data); out_err_free_ctx: kfree(ctx); out_err: return PTR_ERR(p); }
static int gss_import_sec_context_spkm3(const void *p, size_t len, struct gss_ctx *ctx_id) { const void *end = (const void *)((const char *)p + len); struct spkm3_ctx *ctx; int version; if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL))) goto out_err; p = simple_get_bytes(p, end, &version, sizeof(version)); if (IS_ERR(p)) goto out_err_free_ctx; if (version != 1) { dprintk("RPC: unknown spkm3 token format: " "obsolete nfs-utils?\n"); goto out_err_free_ctx; } p = simple_get_netobj(p, end, &ctx->ctx_id); if (IS_ERR(p)) goto out_err_free_ctx; p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); if (IS_ERR(p)) goto out_err_free_ctx_id; p = simple_get_netobj(p, end, &ctx->mech_used); if (IS_ERR(p)) goto out_err_free_ctx_id; p = simple_get_bytes(p, end, &ctx->ret_flags, sizeof(ctx->ret_flags)); if (IS_ERR(p)) goto out_err_free_mech; p = simple_get_netobj(p, end, &ctx->conf_alg); if (IS_ERR(p)) goto out_err_free_mech; p = simple_get_netobj(p, end, &ctx->derived_conf_key); if (IS_ERR(p)) goto out_err_free_conf_alg; p = simple_get_netobj(p, end, &ctx->intg_alg); if (IS_ERR(p)) goto out_err_free_conf_key; p = simple_get_netobj(p, end, &ctx->derived_integ_key); if (IS_ERR(p)) goto out_err_free_intg_alg; if (p != end) goto out_err_free_intg_key; ctx_id->internal_ctx_id = ctx; dprintk("RPC: Successfully imported new spkm context.\n"); return 0; out_err_free_intg_key: kfree(ctx->derived_integ_key.data); out_err_free_intg_alg: kfree(ctx->intg_alg.data); out_err_free_conf_key: kfree(ctx->derived_conf_key.data); out_err_free_conf_alg: kfree(ctx->conf_alg.data); out_err_free_mech: kfree(ctx->mech_used.data); out_err_free_ctx_id: kfree(ctx->ctx_id.data); out_err_free_ctx: kfree(ctx); out_err: return PTR_ERR(p); }