linux/net/sunrpc/auth_gss/gss_mech_switch.c
<<
>>
Prefs
   1/*
   2 *  linux/net/sunrpc/gss_mech_switch.c
   3 *
   4 *  Copyright (c) 2001 The Regents of the University of Michigan.
   5 *  All rights reserved.
   6 *
   7 *  J. Bruce Fields   <bfields@umich.edu>
   8 *
   9 *  Redistribution and use in source and binary forms, with or without
  10 *  modification, are permitted provided that the following conditions
  11 *  are met:
  12 *
  13 *  1. Redistributions of source code must retain the above copyright
  14 *     notice, this list of conditions and the following disclaimer.
  15 *  2. Redistributions in binary form must reproduce the above copyright
  16 *     notice, this list of conditions and the following disclaimer in the
  17 *     documentation and/or other materials provided with the distribution.
  18 *  3. Neither the name of the University nor the names of its
  19 *     contributors may be used to endorse or promote products derived
  20 *     from this software without specific prior written permission.
  21 *
  22 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  23 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  24 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  25 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  29 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  30 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  31 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33 *
  34 */
  35
  36#include <linux/types.h>
  37#include <linux/slab.h>
  38#include <linux/module.h>
  39#include <linux/sunrpc/msg_prot.h>
  40#include <linux/sunrpc/gss_asn1.h>
  41#include <linux/sunrpc/auth_gss.h>
  42#include <linux/sunrpc/svcauth_gss.h>
  43#include <linux/sunrpc/gss_err.h>
  44#include <linux/sunrpc/sched.h>
  45#include <linux/sunrpc/gss_api.h>
  46#include <linux/sunrpc/clnt.h>
  47
  48#ifdef RPC_DEBUG
  49# define RPCDBG_FACILITY        RPCDBG_AUTH
  50#endif
  51
  52static LIST_HEAD(registered_mechs);
  53static DEFINE_SPINLOCK(registered_mechs_lock);
  54
  55static void
  56gss_mech_free(struct gss_api_mech *gm)
  57{
  58        struct pf_desc *pf;
  59        int i;
  60
  61        for (i = 0; i < gm->gm_pf_num; i++) {
  62                pf = &gm->gm_pfs[i];
  63                kfree(pf->auth_domain_name);
  64                pf->auth_domain_name = NULL;
  65        }
  66}
  67
  68static inline char *
  69make_auth_domain_name(char *name)
  70{
  71        static char     *prefix = "gss/";
  72        char            *new;
  73
  74        new = kmalloc(strlen(name) + strlen(prefix) + 1, GFP_KERNEL);
  75        if (new) {
  76                strcpy(new, prefix);
  77                strcat(new, name);
  78        }
  79        return new;
  80}
  81
  82static int
  83gss_mech_svc_setup(struct gss_api_mech *gm)
  84{
  85        struct pf_desc *pf;
  86        int i, status;
  87
  88        for (i = 0; i < gm->gm_pf_num; i++) {
  89                pf = &gm->gm_pfs[i];
  90                pf->auth_domain_name = make_auth_domain_name(pf->name);
  91                status = -ENOMEM;
  92                if (pf->auth_domain_name == NULL)
  93                        goto out;
  94                status = svcauth_gss_register_pseudoflavor(pf->pseudoflavor,
  95                                                        pf->auth_domain_name);
  96                if (status)
  97                        goto out;
  98        }
  99        return 0;
 100out:
 101        gss_mech_free(gm);
 102        return status;
 103}
 104
 105int
 106gss_mech_register(struct gss_api_mech *gm)
 107{
 108        int status;
 109
 110        status = gss_mech_svc_setup(gm);
 111        if (status)
 112                return status;
 113        spin_lock(&registered_mechs_lock);
 114        list_add(&gm->gm_list, &registered_mechs);
 115        spin_unlock(&registered_mechs_lock);
 116        dprintk("RPC:       registered gss mechanism %s\n", gm->gm_name);
 117        return 0;
 118}
 119
 120EXPORT_SYMBOL_GPL(gss_mech_register);
 121
 122void
 123gss_mech_unregister(struct gss_api_mech *gm)
 124{
 125        spin_lock(&registered_mechs_lock);
 126        list_del(&gm->gm_list);
 127        spin_unlock(&registered_mechs_lock);
 128        dprintk("RPC:       unregistered gss mechanism %s\n", gm->gm_name);
 129        gss_mech_free(gm);
 130}
 131
 132EXPORT_SYMBOL_GPL(gss_mech_unregister);
 133
 134struct gss_api_mech *
 135gss_mech_get(struct gss_api_mech *gm)
 136{
 137        __module_get(gm->gm_owner);
 138        return gm;
 139}
 140
 141EXPORT_SYMBOL_GPL(gss_mech_get);
 142
 143struct gss_api_mech *
 144gss_mech_get_by_name(const char *name)
 145{
 146        struct gss_api_mech     *pos, *gm = NULL;
 147
 148        spin_lock(&registered_mechs_lock);
 149        list_for_each_entry(pos, &registered_mechs, gm_list) {
 150                if (0 == strcmp(name, pos->gm_name)) {
 151                        if (try_module_get(pos->gm_owner))
 152                                gm = pos;
 153                        break;
 154                }
 155        }
 156        spin_unlock(&registered_mechs_lock);
 157        return gm;
 158
 159}
 160
 161EXPORT_SYMBOL_GPL(gss_mech_get_by_name);
 162
 163static inline int
 164mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
 165{
 166        int i;
 167
 168        for (i = 0; i < gm->gm_pf_num; i++) {
 169                if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)
 170                        return 1;
 171        }
 172        return 0;
 173}
 174
 175struct gss_api_mech *
 176gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
 177{
 178        struct gss_api_mech *pos, *gm = NULL;
 179
 180        spin_lock(&registered_mechs_lock);
 181        list_for_each_entry(pos, &registered_mechs, gm_list) {
 182                if (!mech_supports_pseudoflavor(pos, pseudoflavor)) {
 183                        module_put(pos->gm_owner);
 184                        continue;
 185                }
 186                if (try_module_get(pos->gm_owner))
 187                        gm = pos;
 188                break;
 189        }
 190        spin_unlock(&registered_mechs_lock);
 191        return gm;
 192}
 193
 194EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor);
 195
 196u32
 197gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
 198{
 199        int i;
 200
 201        for (i = 0; i < gm->gm_pf_num; i++) {
 202                if (gm->gm_pfs[i].service == service) {
 203                        return gm->gm_pfs[i].pseudoflavor;
 204                }
 205        }
 206        return RPC_AUTH_MAXFLAVOR; /* illegal value */
 207}
 208EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor);
 209
 210u32
 211gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
 212{
 213        int i;
 214
 215        for (i = 0; i < gm->gm_pf_num; i++) {
 216                if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)
 217                        return gm->gm_pfs[i].service;
 218        }
 219        return 0;
 220}
 221
 222EXPORT_SYMBOL_GPL(gss_pseudoflavor_to_service);
 223
 224char *
 225gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
 226{
 227        int i;
 228
 229        for (i = 0; i < gm->gm_pf_num; i++) {
 230                if (gm->gm_pfs[i].service == service)
 231                        return gm->gm_pfs[i].auth_domain_name;
 232        }
 233        return NULL;
 234}
 235
 236EXPORT_SYMBOL_GPL(gss_service_to_auth_domain_name);
 237
 238void
 239gss_mech_put(struct gss_api_mech * gm)
 240{
 241        if (gm)
 242                module_put(gm->gm_owner);
 243}
 244
 245EXPORT_SYMBOL_GPL(gss_mech_put);
 246
 247/* The mech could probably be determined from the token instead, but it's just
 248 * as easy for now to pass it in. */
 249int
 250gss_import_sec_context(const void *input_token, size_t bufsize,
 251                       struct gss_api_mech      *mech,
 252                       struct gss_ctx           **ctx_id)
 253{
 254        if (!(*ctx_id = kzalloc(sizeof(**ctx_id), GFP_KERNEL)))
 255                return GSS_S_FAILURE;
 256        (*ctx_id)->mech_type = gss_mech_get(mech);
 257
 258        return mech->gm_ops
 259                ->gss_import_sec_context(input_token, bufsize, *ctx_id);
 260}
 261
 262/* gss_get_mic: compute a mic over message and return mic_token. */
 263
 264u32
 265gss_get_mic(struct gss_ctx      *context_handle,
 266            struct xdr_buf      *message,
 267            struct xdr_netobj   *mic_token)
 268{
 269         return context_handle->mech_type->gm_ops
 270                ->gss_get_mic(context_handle,
 271                              message,
 272                              mic_token);
 273}
 274
 275/* gss_verify_mic: check whether the provided mic_token verifies message. */
 276
 277u32
 278gss_verify_mic(struct gss_ctx           *context_handle,
 279               struct xdr_buf           *message,
 280               struct xdr_netobj        *mic_token)
 281{
 282        return context_handle->mech_type->gm_ops
 283                ->gss_verify_mic(context_handle,
 284                                 message,
 285                                 mic_token);
 286}
 287
 288u32
 289gss_wrap(struct gss_ctx *ctx_id,
 290         int            offset,
 291         struct xdr_buf *buf,
 292         struct page    **inpages)
 293{
 294        return ctx_id->mech_type->gm_ops
 295                ->gss_wrap(ctx_id, offset, buf, inpages);
 296}
 297
 298u32
 299gss_unwrap(struct gss_ctx       *ctx_id,
 300           int                  offset,
 301           struct xdr_buf       *buf)
 302{
 303        return ctx_id->mech_type->gm_ops
 304                ->gss_unwrap(ctx_id, offset, buf);
 305}
 306
 307
 308/* gss_delete_sec_context: free all resources associated with context_handle.
 309 * Note this differs from the RFC 2744-specified prototype in that we don't
 310 * bother returning an output token, since it would never be used anyway. */
 311
 312u32
 313gss_delete_sec_context(struct gss_ctx   **context_handle)
 314{
 315        dprintk("RPC:       gss_delete_sec_context deleting %p\n",
 316                        *context_handle);
 317
 318        if (!*context_handle)
 319                return(GSS_S_NO_CONTEXT);
 320        if ((*context_handle)->internal_ctx_id)
 321                (*context_handle)->mech_type->gm_ops
 322                        ->gss_delete_sec_context((*context_handle)
 323                                                        ->internal_ctx_id);
 324        gss_mech_put((*context_handle)->mech_type);
 325        kfree(*context_handle);
 326        *context_handle=NULL;
 327        return GSS_S_COMPLETE;
 328}
 329