summaryrefslogtreecommitdiff
path: root/net/sunrpc
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@fys.uio.no>2004-08-23 11:00:16 -0400
committerTrond Myklebust <trond.myklebust@fys.uio.no>2004-08-23 11:00:16 -0400
commitecebe0fc94c326fdee96ae7189a2913fa46ced74 (patch)
tree159c2ebc7c35b1c1379c13710bff44f088dd95c3 /net/sunrpc
parentf18badd1890b8fab776e59a902968c846ea42f0f (diff)
parente143b1c817e8403679a39253194cd5b176cfcd53 (diff)
Merge http://nfsclient.bkbits.net/linux-2.6
into fys.uio.no:/home/linux/bitkeeper/nfsclient-2.6
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/auth_gss/Makefile4
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c2
-rw-r--r--net/sunrpc/auth_gss/gss_generic_token.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_unseal.c2
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_mech.c296
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_seal.c132
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_token.c266
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_unseal.c128
-rw-r--r--net/sunrpc/clnt.c41
9 files changed, 859 insertions, 14 deletions
diff --git a/net/sunrpc/auth_gss/Makefile b/net/sunrpc/auth_gss/Makefile
index 9495e527864b..fe1b874084bc 100644
--- a/net/sunrpc/auth_gss/Makefile
+++ b/net/sunrpc/auth_gss/Makefile
@@ -12,3 +12,7 @@ obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \
gss_krb5_seqnum.o
+obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o
+
+rpcsec_gss_spkm3-objs := gss_spkm3_mech.o gss_spkm3_seal.o gss_spkm3_unseal.o \
+ gss_spkm3_token.o
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index e32f2a709e2d..cceea09bddc0 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -397,7 +397,7 @@ retry:
spin_unlock(&gss_auth->lock);
}
gss_release_msg(gss_msg);
- dprintk("RPC: %4u gss_upcall for uid %u result %d", task->tk_pid,
+ dprintk("RPC: %4u gss_upcall for uid %u result %d\n", task->tk_pid,
uid, res);
return res;
out_sleep:
diff --git a/net/sunrpc/auth_gss/gss_generic_token.c b/net/sunrpc/auth_gss/gss_generic_token.c
index d7b040809dd3..b0951d11522a 100644
--- a/net/sunrpc/auth_gss/gss_generic_token.c
+++ b/net/sunrpc/auth_gss/gss_generic_token.c
@@ -179,7 +179,7 @@ EXPORT_SYMBOL(g_make_token_header);
*/
u32
g_verify_token_header(struct xdr_netobj *mech, int *body_size,
- unsigned char **buf_in, int tok_type, int toksize)
+ unsigned char **buf_in, int toksize)
{
unsigned char *buf = *buf_in;
int seqsize;
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index dcde40fe7427..8767fc53183d 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -96,7 +96,7 @@ krb5_read_token(struct krb5_ctx *ctx,
dprintk("RPC: krb5_read_token\n");
- if (g_verify_token_header(&ctx->mech_used, &bodysize, &ptr, toktype,
+ if (g_verify_token_header(&ctx->mech_used, &bodysize, &ptr,
read_token->len))
goto out;
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
new file mode 100644
index 000000000000..2887de1cae1c
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
@@ -0,0 +1,296 @@
+/*
+ * linux/net/sunrpc/gss_spkm3_mech.c
+ *
+ * Copyright (c) 2003 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Andy Adamson <andros@umich.edu>
+ * J. Bruce Fields <bfields@umich.edu>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/in.h>
+#include <linux/sunrpc/svcauth_gss.h>
+#include <linux/sunrpc/gss_spkm3.h>
+#include <linux/sunrpc/xdr.h>
+#include <linux/crypto.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY RPCDBG_AUTH
+#endif
+
+struct xdr_netobj gss_mech_spkm3_oid =
+ {7, "\053\006\001\005\005\001\003"};
+
+static inline int
+get_bytes(char **ptr, const char *end, void *res, int len)
+{
+ char *p, *q;
+ p = *ptr;
+ q = p + len;
+ if (q > end || q < p)
+ return -1;
+ memcpy(res, p, len);
+ *ptr = q;
+ return 0;
+}
+
+static inline int
+get_netobj(char **ptr, const char *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(res->len == 0)
+ goto out_nocopy;
+ if (q > end || q < p)
+ return -1;
+ if (!(res->data = kmalloc(res->len, GFP_KERNEL)))
+ return -1;
+ memcpy(res->data, p, res->len);
+out_nocopy:
+ *ptr = q;
+ return 0;
+}
+
+static inline int
+get_key(char **p, char *end, struct crypto_tfm **res, int *resalg)
+{
+ struct xdr_netobj key = {
+ .len = 0,
+ .data = NULL,
+ };
+ int alg_mode,setkey = 0;
+ char *alg_name;
+
+ if (get_bytes(p, end, resalg, sizeof(int)))
+ goto out_err;
+ if ((get_netobj(p, end, &key)))
+ goto out_err;
+
+ switch (*resalg) {
+ case NID_des_cbc:
+ alg_name = "des";
+ alg_mode = CRYPTO_TFM_MODE_CBC;
+ setkey = 1;
+ break;
+ case NID_md5:
+ if (key.len == 0) {
+ dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n");
+ }
+ alg_name = "md5";
+ alg_mode = 0;
+ setkey = 0;
+ break;
+ case NID_cast5_cbc:
+ dprintk("RPC: SPKM3 get_key: case cast5_cbc, UNSUPPORTED \n");
+ goto out_err;
+ break;
+ default:
+ dprintk("RPC: SPKM3 get_key: unsupported algorithm %d", *resalg);
+ goto out_err_free_key;
+ }
+ if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
+ goto out_err_free_key;
+ if (setkey) {
+ if (crypto_cipher_setkey(*res, key.data, key.len))
+ goto out_err_free_tfm;
+ }
+
+ if(key.len > 0)
+ kfree(key.data);
+ return 0;
+
+out_err_free_tfm:
+ crypto_free_tfm(*res);
+out_err_free_key:
+ if(key.len > 0)
+ kfree(key.data);
+out_err:
+ return -1;
+}
+
+static u32
+gss_import_sec_context_spkm3(struct xdr_netobj *inbuf,
+ struct gss_ctx *ctx_id)
+{
+ char *p = inbuf->data;
+ char *end = inbuf->data + inbuf->len;
+ struct spkm3_ctx *ctx;
+
+ if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
+ goto out_err;
+ memset(ctx, 0, sizeof(*ctx));
+
+ if (get_netobj(&p, end, &ctx->ctx_id))
+ goto out_err_free_ctx;
+
+ if (get_bytes(&p, end, &ctx->qop, sizeof(ctx->qop)))
+ goto out_err_free_ctx_id;
+
+ if (get_netobj(&p, end, &ctx->mech_used))
+ goto out_err_free_mech;
+
+ if (get_bytes(&p, end, &ctx->ret_flags, sizeof(ctx->ret_flags)))
+ goto out_err_free_mech;
+
+ if (get_bytes(&p, end, &ctx->req_flags, sizeof(ctx->req_flags)))
+ goto out_err_free_mech;
+
+ if (get_netobj(&p, end, &ctx->share_key))
+ goto out_err_free_s_key;
+
+ if (get_key(&p, end, &ctx->derived_conf_key, &ctx->conf_alg)) {
+ dprintk("RPC: SPKM3 confidentiality key will be NULL\n");
+ }
+
+ if (get_key(&p, end, &ctx->derived_integ_key, &ctx->intg_alg)) {
+ dprintk("RPC: SPKM3 integrity key will be NULL\n");
+ }
+
+ if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
+ goto out_err_free_s_key;
+
+ if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
+ goto out_err_free_s_key;
+
+ if (p != end)
+ goto out_err_free_s_key;
+
+ ctx_id->internal_ctx_id = ctx;
+
+ dprintk("Succesfully imported new spkm context.\n");
+ return 0;
+
+out_err_free_s_key:
+ kfree(ctx->share_key.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 GSS_S_FAILURE;
+}
+
+void
+gss_delete_sec_context_spkm3(void *internal_ctx) {
+ struct spkm3_ctx *sctx = internal_ctx;
+
+ if(sctx->derived_integ_key)
+ crypto_free_tfm(sctx->derived_integ_key);
+ if(sctx->derived_conf_key)
+ crypto_free_tfm(sctx->derived_conf_key);
+ if(sctx->share_key.data)
+ kfree(sctx->share_key.data);
+ if(sctx->mech_used.data)
+ kfree(sctx->mech_used.data);
+ kfree(sctx);
+}
+
+u32
+gss_verify_mic_spkm3(struct gss_ctx *ctx,
+ struct xdr_buf *signbuf,
+ struct xdr_netobj *checksum,
+ u32 *qstate) {
+ u32 maj_stat = 0;
+ int qop_state = 0;
+ struct spkm3_ctx *sctx = ctx->internal_ctx_id;
+
+ dprintk("RPC: gss_verify_mic_spkm3 calling spkm3_read_token\n");
+ maj_stat = spkm3_read_token(sctx, checksum, signbuf, &qop_state,
+ SPKM_MIC_TOK);
+
+ if (!maj_stat && qop_state)
+ *qstate = qop_state;
+
+ dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat);
+ return maj_stat;
+}
+
+u32
+gss_get_mic_spkm3(struct gss_ctx *ctx,
+ u32 qop,
+ struct xdr_buf *message_buffer,
+ struct xdr_netobj *message_token) {
+ u32 err = 0;
+ struct spkm3_ctx *sctx = ctx->internal_ctx_id;
+
+ dprintk("RPC: gss_get_mic_spkm3\n");
+
+ err = spkm3_make_token(sctx, qop, message_buffer,
+ message_token, SPKM_MIC_TOK);
+ return err;
+}
+
+static struct gss_api_ops gss_spkm3_ops = {
+ .gss_import_sec_context = gss_import_sec_context_spkm3,
+ .gss_get_mic = gss_get_mic_spkm3,
+ .gss_verify_mic = gss_verify_mic_spkm3,
+ .gss_delete_sec_context = gss_delete_sec_context_spkm3,
+};
+
+static struct pf_desc gss_spkm3_pfs[] = {
+ {RPC_AUTH_GSS_SPKM, 0, RPC_GSS_SVC_NONE, "spkm3"},
+ {RPC_AUTH_GSS_SPKMI, 0, RPC_GSS_SVC_INTEGRITY, "spkm3i"},
+};
+
+static struct gss_api_mech gss_spkm3_mech = {
+ .gm_name = "spkm3",
+ .gm_owner = THIS_MODULE,
+ .gm_ops = &gss_spkm3_ops,
+ .gm_pf_num = ARRAY_SIZE(gss_spkm3_pfs),
+ .gm_pfs = gss_spkm3_pfs,
+};
+
+static int __init init_spkm3_module(void)
+{
+ int status;
+
+ status = gss_mech_register(&gss_spkm3_mech);
+ if (status)
+ printk("Failed to register spkm3 gss mechanism!\n");
+ return 0;
+}
+
+static void __exit cleanup_spkm3_module(void)
+{
+ gss_mech_unregister(&gss_spkm3_mech);
+}
+
+MODULE_LICENSE("GPL");
+module_init(init_spkm3_module);
+module_exit(cleanup_spkm3_module);
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
new file mode 100644
index 000000000000..289ed358b7e5
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c
@@ -0,0 +1,132 @@
+/*
+ * linux/net/sunrpc/gss_spkm3_seal.c
+ *
+ * Copyright (c) 2003 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Andy Adamson <andros@umich.edu>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/sunrpc/gss_spkm3.h>
+#include <linux/random.h>
+#include <linux/crypto.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY RPCDBG_AUTH
+#endif
+
+/*
+ * spkm3_make_token()
+ *
+ * Only SPKM_MIC_TOK with md5 intg-alg is supported
+ */
+
+u32
+spkm3_make_token(struct spkm3_ctx *ctx, int qop_req,
+ struct xdr_buf * text, struct xdr_netobj * token,
+ int toktype)
+{
+ s32 checksum_type;
+ char tokhdrbuf[25];
+ struct xdr_netobj md5cksum = {.len = 0, .data = NULL};
+ struct xdr_netobj mic_hdr = {.len = 0, .data = tokhdrbuf};
+ int tmsglen, tokenlen = 0;
+ unsigned char *ptr;
+ s32 now;
+ int ctxelen = 0, ctxzbit = 0;
+ int md5elen = 0, md5zbit = 0;
+
+ dprintk("RPC: spkm3_make_token\n");
+
+ now = jiffies;
+ if (qop_req != 0)
+ goto out_err;
+
+ if (ctx->ctx_id.len != 16) {
+ dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n",
+ ctx->ctx_id.len);
+ goto out_err;
+ }
+
+ switch (ctx->intg_alg) {
+ case NID_md5:
+ checksum_type = CKSUMTYPE_RSA_MD5;
+ break;
+ default:
+ dprintk("RPC: gss_spkm3_seal: ctx->signalg %d not"
+ " supported\n", ctx->intg_alg);
+ goto out_err;
+ }
+ /* XXX since we don't support WRAP, perhaps we don't care... */
+ if (ctx->conf_alg != NID_cast5_cbc) {
+ dprintk("RPC: gss_spkm3_seal: ctx->sealalg %d not supported\n",
+ ctx->conf_alg);
+ goto out_err;
+ }
+
+ if (toktype == SPKM_MIC_TOK) {
+ tmsglen = 0;
+ /* Calculate checksum over the mic-header */
+ asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit);
+ spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data,
+ ctxelen, ctxzbit);
+
+ if (make_checksum(checksum_type, mic_hdr.data, mic_hdr.len,
+ text, &md5cksum))
+ goto out_err;
+
+ asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit);
+ tokenlen = 10 + ctxelen + 1 + 2 + md5elen + 1;
+
+ /* Create token header using generic routines */
+ token->len = g_token_size(&ctx->mech_used, tokenlen + tmsglen);
+
+ ptr = token->data;
+ g_make_token_header(&ctx->mech_used, tokenlen + tmsglen, &ptr);
+
+ spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
+ } else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
+ dprintk("RPC: gss_spkm3_seal: SPKM_WRAP_TOK not supported\n");
+ goto out_err;
+ }
+ kfree(md5cksum.data);
+
+ /* XXX need to implement sequence numbers, and ctx->expired */
+
+ return GSS_S_COMPLETE;
+out_err:
+ if (md5cksum.data)
+ kfree(md5cksum.data);
+ token->data = 0;
+ token->len = 0;
+ return GSS_S_FAILURE;
+}
diff --git a/net/sunrpc/auth_gss/gss_spkm3_token.c b/net/sunrpc/auth_gss/gss_spkm3_token.c
new file mode 100644
index 000000000000..46c08a0710f6
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_spkm3_token.c
@@ -0,0 +1,266 @@
+/*
+ * linux/net/sunrpc/gss_spkm3_token.c
+ *
+ * Copyright (c) 2003 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Andy Adamson <andros@umich.edu>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/sunrpc/gss_spkm3.h>
+#include <linux/random.h>
+#include <linux/crypto.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY RPCDBG_AUTH
+#endif
+
+/*
+ * asn1_bitstring_len()
+ *
+ * calculate the asn1 bitstring length of the xdr_netobject
+ */
+void
+asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits)
+{
+ int i, zbit = 0,elen = in->len;
+ char *ptr;
+
+ ptr = &in->data[in->len -1];
+
+ /* count trailing 0's */
+ for(i = in->len; i > 0; i--) {
+ if (*ptr == 0) {
+ ptr--;
+ elen--;
+ } else
+ break;
+ }
+
+ /* count number of 0 bits in final octet */
+ ptr = &in->data[elen - 1];
+ for(i = 0; i < 8; i++) {
+ short mask = 0x01;
+
+ if (!((mask << i) & *ptr))
+ zbit++;
+ else
+ break;
+ }
+ *enclen = elen;
+ *zerobits = zbit;
+}
+
+/*
+ * decode_asn1_bitstring()
+ *
+ * decode a bitstring into a buffer of the expected length.
+ * enclen = bit string length
+ * explen = expected length (define in rfc)
+ */
+int
+decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen)
+{
+ if (!(out->data = kmalloc(explen,GFP_KERNEL)))
+ return 0;
+ out->len = explen;
+ memset(out->data, 0, explen);
+ memcpy(out->data, in, enclen);
+ return 1;
+}
+
+/*
+ * SPKMInnerContextToken choice SPKM_MIC asn1 token layout
+ *
+ * contextid is always 16 bytes plain data. max asn1 bitstring len = 17.
+ *
+ * tokenlen = pos[0] to end of token (max pos[45] with MD5 cksum)
+ *
+ * pos value
+ * ----------
+ * [0] a4 SPKM-MIC tag
+ * [1] ?? innertoken length (max 44)
+ *
+ *
+ * tok_hdr piece of checksum data starts here
+ *
+ * the maximum mic-header len = 9 + 17 = 26
+ * mic-header
+ * ----------
+ * [2] 30 SEQUENCE tag
+ * [3] ?? mic-header length: (max 23) = TokenID + ContextID
+ *
+ * TokenID - all fields constant and can be hardcoded
+ * -------
+ * [4] 02 Type 2
+ * [5] 02 Length 2
+ * [6][7] 01 01 TokenID (SPKM_MIC_TOK)
+ *
+ * ContextID - encoded length not constant, calculated
+ * ---------
+ * [8] 03 Type 3
+ * [9] ?? encoded length
+ * [10] ?? ctxzbit
+ * [11] contextid
+ *
+ * mic_header piece of checksum data ends here.
+ *
+ * int-cksum - encoded length not constant, calculated
+ * ---------
+ * [??] 03 Type 3
+ * [??] ?? encoded length
+ * [??] ?? md5zbit
+ * [??] int-cksum (NID_md5 = 16)
+ *
+ * maximum SPKM-MIC innercontext token length =
+ * 10 + encoded contextid_size(17 max) + 2 + encoded
+ * cksum_size (17 maxfor NID_md5) = 46
+ */
+
+/*
+ * spkm3_mic_header()
+ *
+ * Prepare the SPKM_MIC_TOK mic-header for check-sum calculation
+ * elen: 16 byte context id asn1 bitstring encoded length
+ */
+void
+spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, unsigned char *ctxdata, int elen, int zbit)
+{
+ char *hptr = *hdrbuf;
+ char *top = *hdrbuf;
+
+ *(u8 *)hptr++ = 0x30;
+ *(u8 *)hptr++ = elen + 7; /* on the wire header length */
+
+ /* tokenid */
+ *(u8 *)hptr++ = 0x02;
+ *(u8 *)hptr++ = 0x02;
+ *(u8 *)hptr++ = 0x01;
+ *(u8 *)hptr++ = 0x01;
+
+ /* coniextid */
+ *(u8 *)hptr++ = 0x03;
+ *(u8 *)hptr++ = elen + 1; /* add 1 to include zbit */
+ *(u8 *)hptr++ = zbit;
+ memcpy(hptr, ctxdata, elen);
+ hptr += elen;
+ *hdrlen = hptr - top;
+}
+
+/*
+ * spkm3_mic_innercontext_token()
+ *
+ * *tokp points to the beginning of the SPKM_MIC token described
+ * in rfc 2025, section 3.2.1:
+ *
+ */
+void
+spkm3_make_mic_token(unsigned char **tokp, int toklen, struct xdr_netobj *mic_hdr, struct xdr_netobj *md5cksum, int md5elen, int md5zbit)
+{
+ unsigned char *ict = *tokp;
+
+ *(u8 *)ict++ = 0xa4;
+ *(u8 *)ict++ = toklen - 2;
+ memcpy(ict, mic_hdr->data, mic_hdr->len);
+ ict += mic_hdr->len;
+
+ *(u8 *)ict++ = 0x03;
+ *(u8 *)ict++ = md5elen + 1; /* add 1 to include zbit */
+ *(u8 *)ict++ = md5zbit;
+ memcpy(ict, md5cksum->data, md5elen);
+}
+
+u32
+spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **cksum)
+{
+ struct xdr_netobj spkm3_ctx_id = {.len =0, .data = NULL};
+ unsigned char *ptr = *tokp;
+ int ctxelen;
+ u32 ret = GSS_S_DEFECTIVE_TOKEN;
+
+ /* spkm3 innercontext token preamble */
+ if ((ptr[0] != 0xa4) || (ptr[2] != 0x30)) {
+ dprintk("RPC: BAD SPKM ictoken preamble\n");
+ goto out;
+ }
+
+ *mic_hdrlen = ptr[3];
+
+ /* token type */
+ if ((ptr[4] != 0x02) || (ptr[5] != 0x02)) {
+ dprintk("RPC: BAD asn1 SPKM3 token type\n");
+ goto out;
+ }
+
+ /* only support SPKM_MIC_TOK */
+ if((ptr[6] != 0x01) || (ptr[7] != 0x01)) {
+ dprintk("RPC: ERROR unsupported SPKM3 token \n");
+ goto out;
+ }
+
+ /* contextid */
+ if (ptr[8] != 0x03) {
+ dprintk("RPC: BAD SPKM3 asn1 context-id type\n");
+ goto out;
+ }
+
+ ctxelen = ptr[9];
+ if (ctxelen > 17) { /* length includes asn1 zbit octet */
+ dprintk("RPC: BAD SPKM3 contextid len %d\n", ctxelen);
+ goto out;
+ }
+
+ /* ignore ptr[10] */
+
+ if(!decode_asn1_bitstring(&spkm3_ctx_id, &ptr[11], ctxelen - 1, 16))
+ goto out;
+
+ /*
+ * in the current implementation: the optional int-alg is not present
+ * so the default int-alg (md5) is used the optional snd-seq field is
+ * also not present
+ */
+
+ if (*mic_hdrlen != 6 + ctxelen) {
+ dprintk("RPC: BAD SPKM_ MIC_TOK header len %d: we only support default int-alg (should be absent) and do not support snd-seq\n", *mic_hdrlen);
+ goto out;
+ }
+ /* checksum */
+ *cksum = (&ptr[10] + ctxelen); /* ctxelen includes ptr[10] */
+
+ ret = GSS_S_COMPLETE;
+out:
+ if (spkm3_ctx_id.data)
+ kfree(spkm3_ctx_id.data);
+ return ret;
+}
+
diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c
new file mode 100644
index 000000000000..65ce81bf0bc4
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_spkm3_unseal.c
@@ -0,0 +1,128 @@
+/*
+ * linux/net/sunrpc/gss_spkm3_unseal.c
+ *
+ * Copyright (c) 2003 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Andy Adamson <andros@umich.edu>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/sunrpc/gss_spkm3.h>
+#include <linux/crypto.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY RPCDBG_AUTH
+#endif
+
+/*
+ * spkm3_read_token()
+ *
+ * only SPKM_MIC_TOK with md5 intg-alg is supported
+ */
+u32
+spkm3_read_token(struct spkm3_ctx *ctx,
+ struct xdr_netobj *read_token, /* checksum */
+ struct xdr_buf *message_buffer, /* signbuf */
+ int *qop_state, int toktype)
+{
+ s32 code;
+ struct xdr_netobj wire_cksum = {.len =0, .data = NULL};
+ struct xdr_netobj md5cksum = {.len = 0, .data = NULL};
+ unsigned char *ptr = (unsigned char *)read_token->data;
+ unsigned char *cksum;
+ int bodysize, md5elen;
+ int mic_hdrlen;
+ u32 ret = GSS_S_DEFECTIVE_TOKEN;
+
+ dprintk("RPC: spkm3_read_token read_token->len %d\n", read_token->len);
+
+ if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used,
+ &bodysize, &ptr, read_token->len))
+ goto out;
+
+ /* decode the token */
+
+ if (toktype == SPKM_MIC_TOK) {
+
+ if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum)))
+ goto out;
+
+ if (*cksum++ != 0x03) {
+ dprintk("RPC: spkm3_read_token BAD checksum type\n");
+ goto out;
+ }
+ md5elen = *cksum++;
+ cksum++; /* move past the zbit */
+
+ if(!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16))
+ goto out;
+
+ /* HARD CODED FOR MD5 */
+
+ /* compute the checksum of the message.
+ * ptr + 2 = start of header piece of checksum
+ * mic_hdrlen + 2 = length of header piece of checksum
+ */
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2,
+ mic_hdrlen + 2,
+ message_buffer, &md5cksum);
+
+ if (code)
+ goto out;
+
+ dprintk("RPC: spkm3_read_token: digest wire_cksum.len %d:\n",
+ wire_cksum.len);
+ dprintk(" md5cksum.data\n");
+ print_hexl((u32 *) md5cksum.data, 16, 0);
+ dprintk(" cksum.data:\n");
+ print_hexl((u32 *) wire_cksum.data, wire_cksum.len, 0);
+
+ ret = GSS_S_BAD_SIG;
+ code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len);
+ if (code)
+ goto out;
+
+ } else {
+ dprintk("RPC: BAD or UNSUPPORTED SPKM3 token type: %d\n",toktype);
+ goto out;
+ }
+
+ /* XXX: need to add expiration and sequencing */
+ ret = GSS_S_COMPLETE;
+out:
+ if (md5cksum.data)
+ kfree(md5cksum.data);
+ if (wire_cksum.data)
+ kfree(wire_cksum.data);
+ return ret;
+}
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index e0657790127b..4f4cdb904bf3 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -196,7 +196,15 @@ rpc_clone_client(struct rpc_clnt *clnt)
memcpy(new, clnt, sizeof(*new));
atomic_set(&new->cl_count, 1);
atomic_set(&new->cl_users, 0);
- atomic_inc(&new->cl_parent->cl_count);
+ new->cl_parent = clnt;
+ atomic_inc(&clnt->cl_count);
+ /* Duplicate portmapper */
+ rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait");
+ /* Turn off autobind on clones */
+ new->cl_autobind = 0;
+ new->cl_oneshot = 0;
+ new->cl_dead = 0;
+ rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
if (new->cl_auth)
atomic_inc(&new->cl_auth->au_count);
return new;
@@ -335,7 +343,7 @@ void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset)
*/
int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
{
- struct rpc_task my_task, *task = &my_task;
+ struct rpc_task *task;
sigset_t oldset;
int status;
@@ -343,15 +351,15 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
if (clnt->cl_dead)
return -EIO;
- if (flags & RPC_TASK_ASYNC) {
- printk("rpc_call_sync: Illegal flag combination for synchronous task\n");
- flags &= ~RPC_TASK_ASYNC;
- }
+ BUG_ON(flags & RPC_TASK_ASYNC);
rpc_clnt_sigmask(clnt, &oldset);
- /* Create/initialize a new RPC task */
- rpc_init_task(task, clnt, NULL, flags);
+ status = -ENOMEM;
+ task = rpc_new_task(clnt, NULL, flags);
+ if (task == NULL)
+ goto out;
+
rpc_call_setup(task, msg, 0);
/* Set up the call info struct and execute the task */
@@ -362,6 +370,7 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
rpc_release_task(task);
}
+out:
rpc_clnt_sigunmask(clnt, &oldset);
return status;
@@ -958,8 +967,12 @@ call_header(struct rpc_task *task)
static u32 *
call_verify(struct rpc_task *task)
{
- u32 *p = task->tk_rqstp->rq_rcv_buf.head[0].iov_base, n;
+ struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
+ int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
+ u32 *p = iov->iov_base, n;
+ if ((len -= 3) < 0)
+ goto garbage;
p += 1; /* skip XID */
if ((n = ntohl(*p++)) != RPC_REPLY) {
@@ -969,9 +982,11 @@ call_verify(struct rpc_task *task)
if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
int error = -EACCES;
+ if (--len < 0)
+ goto garbage;
if ((n = ntohl(*p++)) != RPC_AUTH_ERROR) {
printk(KERN_WARNING "call_verify: RPC call rejected: %x\n", n);
- } else
+ } else if (--len < 0)
switch ((n = ntohl(*p++))) {
case RPC_AUTH_REJECTEDCRED:
case RPC_AUTH_REJECTEDVERF:
@@ -1002,7 +1017,8 @@ call_verify(struct rpc_task *task)
default:
printk(KERN_WARNING "call_verify: unknown auth error: %x\n", n);
error = -EIO;
- }
+ } else
+ goto garbage;
dprintk("RPC: %4d call_verify: call rejected %d\n",
task->tk_pid, n);
rpc_exit(task, error);
@@ -1012,6 +1028,9 @@ call_verify(struct rpc_task *task)
printk(KERN_WARNING "call_verify: auth check failed\n");
goto garbage; /* bad verifier, retry */
}
+ len = p - (u32 *)iov->iov_base - 1;
+ if (len < 0)
+ goto garbage;
switch ((n = ntohl(*p++))) {
case RPC_SUCCESS:
return p;