1/* 2 * linux/net/sunrpc/gss_spkm3_mech.c 3 * 4 * Copyright (c) 2003 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/in.h> 44#include <linux/sunrpc/svcauth_gss.h> 45#include <linux/sunrpc/gss_spkm3.h> 46#include <linux/sunrpc/xdr.h> 47#include <linux/crypto.h> 48 49#ifdef RPC_DEBUG 50# define RPCDBG_FACILITY RPCDBG_AUTH 51#endif 52 53static const void * 54simple_get_bytes(const void *p, const void *end, void *res, int len) 55{ 56 const void *q = (const void *)((const char *)p + len); 57 if (unlikely(q > end || q < p)) 58 return ERR_PTR(-EFAULT); 59 memcpy(res, p, len); 60 return q; 61} 62 63static const void * 64simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) 65{ 66 const void *q; 67 unsigned int len; 68 p = simple_get_bytes(p, end, &len, sizeof(len)); 69 if (IS_ERR(p)) 70 return p; 71 res->len = len; 72 if (len == 0) { 73 res->data = NULL; 74 return p; 75 } 76 q = (const void *)((const char *)p + len); 77 if (unlikely(q > end || q < p)) 78 return ERR_PTR(-EFAULT); 79 res->data = kmemdup(p, len, GFP_NOFS); 80 if (unlikely(res->data == NULL)) 81 return ERR_PTR(-ENOMEM); 82 return q; 83} 84 85static int 86gss_import_sec_context_spkm3(const void *p, size_t len, 87 struct gss_ctx *ctx_id, 88 gfp_t gfp_mask) 89{ 90 const void *end = (const void *)((const char *)p + len); 91 struct spkm3_ctx *ctx; 92 int version; 93 94 if (!(ctx = kzalloc(sizeof(*ctx), gfp_mask))) 95 goto out_err; 96 97 p = simple_get_bytes(p, end, &version, sizeof(version)); 98 if (IS_ERR(p)) 99 goto out_err_free_ctx; 100 if (version != 1) { 101 dprintk("RPC: unknown spkm3 token format: " 102 "obsolete nfs-utils?\n"); 103 p = ERR_PTR(-EINVAL); 104 goto out_err_free_ctx; 105 } 106 107 p = simple_get_netobj(p, end, &ctx->ctx_id); 108 if (IS_ERR(p)) 109 goto out_err_free_ctx; 110 111 p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); 112 if (IS_ERR(p)) 113 goto out_err_free_ctx_id; 114 115 p = simple_get_netobj(p, end, &ctx->mech_used); 116 if (IS_ERR(p)) 117 goto out_err_free_ctx_id; 118 119 p = simple_get_bytes(p, end, &ctx->ret_flags, sizeof(ctx->ret_flags)); 120 if (IS_ERR(p)) 121 goto out_err_free_mech; 122 123 p = simple_get_netobj(p, end, &ctx->conf_alg); 124 if (IS_ERR(p)) 125 goto out_err_free_mech; 126 127 p = simple_get_netobj(p, end, &ctx->derived_conf_key); 128 if (IS_ERR(p)) 129 goto out_err_free_conf_alg; 130 131 p = simple_get_netobj(p, end, &ctx->intg_alg); 132 if (IS_ERR(p)) 133 goto out_err_free_conf_key; 134 135 p = simple_get_netobj(p, end, &ctx->derived_integ_key); 136 if (IS_ERR(p)) 137 goto out_err_free_intg_alg; 138 139 if (p != end) { 140 p = ERR_PTR(-EFAULT); 141 goto out_err_free_intg_key; 142 } 143 144 ctx_id->internal_ctx_id = ctx; 145 146 dprintk("RPC: Successfully imported new spkm context.\n"); 147 return 0; 148 149out_err_free_intg_key: 150 kfree(ctx->derived_integ_key.data); 151out_err_free_intg_alg: 152 kfree(ctx->intg_alg.data); 153out_err_free_conf_key: 154 kfree(ctx->derived_conf_key.data); 155out_err_free_conf_alg: 156 kfree(ctx->conf_alg.data); 157out_err_free_mech: 158 kfree(ctx->mech_used.data); 159out_err_free_ctx_id: 160 kfree(ctx->ctx_id.data); 161out_err_free_ctx: 162 kfree(ctx); 163out_err: 164 return PTR_ERR(p); 165} 166 167static void 168gss_delete_sec_context_spkm3(void *internal_ctx) 169{ 170 struct spkm3_ctx *sctx = internal_ctx; 171 172 kfree(sctx->derived_integ_key.data); 173 kfree(sctx->intg_alg.data); 174 kfree(sctx->derived_conf_key.data); 175 kfree(sctx->conf_alg.data); 176 kfree(sctx->mech_used.data); 177 kfree(sctx->ctx_id.data); 178 kfree(sctx); 179} 180 181static u32 182gss_verify_mic_spkm3(struct gss_ctx *ctx, 183 struct xdr_buf *signbuf, 184 struct xdr_netobj *checksum) 185{ 186 u32 maj_stat = 0; 187 struct spkm3_ctx *sctx = ctx->internal_ctx_id; 188 189 maj_stat = spkm3_read_token(sctx, checksum, signbuf, SPKM_MIC_TOK); 190 191 dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat); 192 return maj_stat; 193} 194 195static u32 196gss_get_mic_spkm3(struct gss_ctx *ctx, 197 struct xdr_buf *message_buffer, 198 struct xdr_netobj *message_token) 199{ 200 u32 err = 0; 201 struct spkm3_ctx *sctx = ctx->internal_ctx_id; 202 203 err = spkm3_make_token(sctx, message_buffer, 204 message_token, SPKM_MIC_TOK); 205 dprintk("RPC: gss_get_mic_spkm3 returning %d\n", err); 206 return err; 207} 208 209static const struct gss_api_ops gss_spkm3_ops = { 210 .gss_import_sec_context = gss_import_sec_context_spkm3, 211 .gss_get_mic = gss_get_mic_spkm3, 212 .gss_verify_mic = gss_verify_mic_spkm3, 213 .gss_delete_sec_context = gss_delete_sec_context_spkm3, 214}; 215 216static struct pf_desc gss_spkm3_pfs[] = { 217 {RPC_AUTH_GSS_SPKM, RPC_GSS_SVC_NONE, "spkm3"}, 218 {RPC_AUTH_GSS_SPKMI, RPC_GSS_SVC_INTEGRITY, "spkm3i"}, 219}; 220 221static struct gss_api_mech gss_spkm3_mech = { 222 .gm_name = "spkm3", 223 .gm_owner = THIS_MODULE, 224 .gm_oid = {7, "\053\006\001\005\005\001\003"}, 225 .gm_ops = &gss_spkm3_ops, 226 .gm_pf_num = ARRAY_SIZE(gss_spkm3_pfs), 227 .gm_pfs = gss_spkm3_pfs, 228}; 229 230static int __init init_spkm3_module(void) 231{ 232 int status; 233 234 status = gss_mech_register(&gss_spkm3_mech); 235 if (status) 236 printk("Failed to register spkm3 gss mechanism!\n"); 237 return status; 238} 239 240static void __exit cleanup_spkm3_module(void) 241{ 242 gss_mech_unregister(&gss_spkm3_mech); 243} 244 245MODULE_LICENSE("GPL"); 246module_init(init_spkm3_module); 247module_exit(cleanup_spkm3_module); 248