Path: blob/master/net/sunrpc/auth_gss/gss_mech_switch.c
15112 views
/*1* linux/net/sunrpc/gss_mech_switch.c2*3* Copyright (c) 2001 The Regents of the University of Michigan.4* All rights reserved.5*6* J. Bruce Fields <[email protected]>7*8* Redistribution and use in source and binary forms, with or without9* modification, are permitted provided that the following conditions10* are met:11*12* 1. Redistributions of source code must retain the above copyright13* notice, this list of conditions and the following disclaimer.14* 2. Redistributions in binary form must reproduce the above copyright15* notice, this list of conditions and the following disclaimer in the16* documentation and/or other materials provided with the distribution.17* 3. Neither the name of the University nor the names of its18* contributors may be used to endorse or promote products derived19* from this software without specific prior written permission.20*21* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED22* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF23* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE24* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE25* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR26* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF27* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR28* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF29* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING30* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS31* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.32*33*/3435#include <linux/types.h>36#include <linux/slab.h>37#include <linux/module.h>38#include <linux/sunrpc/msg_prot.h>39#include <linux/sunrpc/gss_asn1.h>40#include <linux/sunrpc/auth_gss.h>41#include <linux/sunrpc/svcauth_gss.h>42#include <linux/sunrpc/gss_err.h>43#include <linux/sunrpc/sched.h>44#include <linux/sunrpc/gss_api.h>45#include <linux/sunrpc/clnt.h>4647#ifdef RPC_DEBUG48# define RPCDBG_FACILITY RPCDBG_AUTH49#endif5051static LIST_HEAD(registered_mechs);52static DEFINE_SPINLOCK(registered_mechs_lock);5354static void55gss_mech_free(struct gss_api_mech *gm)56{57struct pf_desc *pf;58int i;5960for (i = 0; i < gm->gm_pf_num; i++) {61pf = &gm->gm_pfs[i];62kfree(pf->auth_domain_name);63pf->auth_domain_name = NULL;64}65}6667static inline char *68make_auth_domain_name(char *name)69{70static char *prefix = "gss/";71char *new;7273new = kmalloc(strlen(name) + strlen(prefix) + 1, GFP_KERNEL);74if (new) {75strcpy(new, prefix);76strcat(new, name);77}78return new;79}8081static int82gss_mech_svc_setup(struct gss_api_mech *gm)83{84struct pf_desc *pf;85int i, status;8687for (i = 0; i < gm->gm_pf_num; i++) {88pf = &gm->gm_pfs[i];89pf->auth_domain_name = make_auth_domain_name(pf->name);90status = -ENOMEM;91if (pf->auth_domain_name == NULL)92goto out;93status = svcauth_gss_register_pseudoflavor(pf->pseudoflavor,94pf->auth_domain_name);95if (status)96goto out;97}98return 0;99out:100gss_mech_free(gm);101return status;102}103104int105gss_mech_register(struct gss_api_mech *gm)106{107int status;108109status = gss_mech_svc_setup(gm);110if (status)111return status;112spin_lock(®istered_mechs_lock);113list_add(&gm->gm_list, ®istered_mechs);114spin_unlock(®istered_mechs_lock);115dprintk("RPC: registered gss mechanism %s\n", gm->gm_name);116return 0;117}118119EXPORT_SYMBOL_GPL(gss_mech_register);120121void122gss_mech_unregister(struct gss_api_mech *gm)123{124spin_lock(®istered_mechs_lock);125list_del(&gm->gm_list);126spin_unlock(®istered_mechs_lock);127dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name);128gss_mech_free(gm);129}130131EXPORT_SYMBOL_GPL(gss_mech_unregister);132133struct gss_api_mech *134gss_mech_get(struct gss_api_mech *gm)135{136__module_get(gm->gm_owner);137return gm;138}139140EXPORT_SYMBOL_GPL(gss_mech_get);141142struct gss_api_mech *143gss_mech_get_by_name(const char *name)144{145struct gss_api_mech *pos, *gm = NULL;146147spin_lock(®istered_mechs_lock);148list_for_each_entry(pos, ®istered_mechs, gm_list) {149if (0 == strcmp(name, pos->gm_name)) {150if (try_module_get(pos->gm_owner))151gm = pos;152break;153}154}155spin_unlock(®istered_mechs_lock);156return gm;157158}159160EXPORT_SYMBOL_GPL(gss_mech_get_by_name);161162struct gss_api_mech *163gss_mech_get_by_OID(struct xdr_netobj *obj)164{165struct gss_api_mech *pos, *gm = NULL;166167spin_lock(®istered_mechs_lock);168list_for_each_entry(pos, ®istered_mechs, gm_list) {169if (obj->len == pos->gm_oid.len) {170if (0 == memcmp(obj->data, pos->gm_oid.data, obj->len)) {171if (try_module_get(pos->gm_owner))172gm = pos;173break;174}175}176}177spin_unlock(®istered_mechs_lock);178return gm;179180}181182EXPORT_SYMBOL_GPL(gss_mech_get_by_OID);183184static inline int185mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)186{187int i;188189for (i = 0; i < gm->gm_pf_num; i++) {190if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)191return 1;192}193return 0;194}195196struct gss_api_mech *197gss_mech_get_by_pseudoflavor(u32 pseudoflavor)198{199struct gss_api_mech *pos, *gm = NULL;200201spin_lock(®istered_mechs_lock);202list_for_each_entry(pos, ®istered_mechs, gm_list) {203if (!mech_supports_pseudoflavor(pos, pseudoflavor)) {204module_put(pos->gm_owner);205continue;206}207if (try_module_get(pos->gm_owner))208gm = pos;209break;210}211spin_unlock(®istered_mechs_lock);212return gm;213}214215EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor);216217int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr)218{219struct gss_api_mech *pos = NULL;220int i = 0;221222spin_lock(®istered_mechs_lock);223list_for_each_entry(pos, ®istered_mechs, gm_list) {224array_ptr[i] = pos->gm_pfs->pseudoflavor;225i++;226}227spin_unlock(®istered_mechs_lock);228return i;229}230231EXPORT_SYMBOL_GPL(gss_mech_list_pseudoflavors);232233u32234gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)235{236int i;237238for (i = 0; i < gm->gm_pf_num; i++) {239if (gm->gm_pfs[i].service == service) {240return gm->gm_pfs[i].pseudoflavor;241}242}243return RPC_AUTH_MAXFLAVOR; /* illegal value */244}245EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor);246247u32248gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)249{250int i;251252for (i = 0; i < gm->gm_pf_num; i++) {253if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)254return gm->gm_pfs[i].service;255}256return 0;257}258259EXPORT_SYMBOL_GPL(gss_pseudoflavor_to_service);260261char *262gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)263{264int i;265266for (i = 0; i < gm->gm_pf_num; i++) {267if (gm->gm_pfs[i].service == service)268return gm->gm_pfs[i].auth_domain_name;269}270return NULL;271}272273EXPORT_SYMBOL_GPL(gss_service_to_auth_domain_name);274275void276gss_mech_put(struct gss_api_mech * gm)277{278if (gm)279module_put(gm->gm_owner);280}281282EXPORT_SYMBOL_GPL(gss_mech_put);283284/* The mech could probably be determined from the token instead, but it's just285* as easy for now to pass it in. */286int287gss_import_sec_context(const void *input_token, size_t bufsize,288struct gss_api_mech *mech,289struct gss_ctx **ctx_id,290gfp_t gfp_mask)291{292if (!(*ctx_id = kzalloc(sizeof(**ctx_id), gfp_mask)))293return -ENOMEM;294(*ctx_id)->mech_type = gss_mech_get(mech);295296return mech->gm_ops297->gss_import_sec_context(input_token, bufsize, *ctx_id, gfp_mask);298}299300/* gss_get_mic: compute a mic over message and return mic_token. */301302u32303gss_get_mic(struct gss_ctx *context_handle,304struct xdr_buf *message,305struct xdr_netobj *mic_token)306{307return context_handle->mech_type->gm_ops308->gss_get_mic(context_handle,309message,310mic_token);311}312313/* gss_verify_mic: check whether the provided mic_token verifies message. */314315u32316gss_verify_mic(struct gss_ctx *context_handle,317struct xdr_buf *message,318struct xdr_netobj *mic_token)319{320return context_handle->mech_type->gm_ops321->gss_verify_mic(context_handle,322message,323mic_token);324}325326/*327* This function is called from both the client and server code.328* Each makes guarantees about how much "slack" space is available329* for the underlying function in "buf"'s head and tail while330* performing the wrap.331*332* The client and server code allocate RPC_MAX_AUTH_SIZE extra333* space in both the head and tail which is available for use by334* the wrap function.335*336* Underlying functions should verify they do not use more than337* RPC_MAX_AUTH_SIZE of extra space in either the head or tail338* when performing the wrap.339*/340u32341gss_wrap(struct gss_ctx *ctx_id,342int offset,343struct xdr_buf *buf,344struct page **inpages)345{346return ctx_id->mech_type->gm_ops347->gss_wrap(ctx_id, offset, buf, inpages);348}349350u32351gss_unwrap(struct gss_ctx *ctx_id,352int offset,353struct xdr_buf *buf)354{355return ctx_id->mech_type->gm_ops356->gss_unwrap(ctx_id, offset, buf);357}358359360/* gss_delete_sec_context: free all resources associated with context_handle.361* Note this differs from the RFC 2744-specified prototype in that we don't362* bother returning an output token, since it would never be used anyway. */363364u32365gss_delete_sec_context(struct gss_ctx **context_handle)366{367dprintk("RPC: gss_delete_sec_context deleting %p\n",368*context_handle);369370if (!*context_handle)371return GSS_S_NO_CONTEXT;372if ((*context_handle)->internal_ctx_id)373(*context_handle)->mech_type->gm_ops374->gss_delete_sec_context((*context_handle)375->internal_ctx_id);376gss_mech_put((*context_handle)->mech_type);377kfree(*context_handle);378*context_handle=NULL;379return GSS_S_COMPLETE;380}381382383