X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsunrpc%2Fauth_gss%2Fgss_mech_switch.c;h=3db745379d060a0d3e0a653636223e3d7d460ab4;hb=refs%2Fheads%2Fvserver;hp=b076e81afab1a3a1aa0a4806cfebb5d808ef941a;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index b076e81af..3db745379 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -35,10 +35,11 @@ #include #include -#include +#include #include #include #include +#include #include #include #include @@ -49,175 +50,210 @@ #endif static LIST_HEAD(registered_mechs); -static spinlock_t registered_mechs_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(registered_mechs_lock); -/* Reference counting: The reference count includes the reference in the - * global registered_mechs list. That reference will never diseappear - * (so the reference count will never go below 1) until after the mech - * is removed from the list. Nothing can be removed from the list without - * first getting the registered_mechs_lock, so a gss_api_mech won't diseappear - * from underneath us while we hold the registered_mech_lock. */ - -int -gss_mech_register(struct xdr_netobj * mech_type, struct gss_api_ops * ops) +static void +gss_mech_free(struct gss_api_mech *gm) { - struct gss_api_mech *gm; + struct pf_desc *pf; + int i; - if (!(gm = kmalloc(sizeof(*gm), GFP_KERNEL))) { - printk("Failed to allocate memory in gss_mech_register"); - return -1; - } - gm->gm_oid.len = mech_type->len; - if (!(gm->gm_oid.data = kmalloc(mech_type->len, GFP_KERNEL))) { - kfree(gm); - printk("Failed to allocate memory in gss_mech_register"); - return -1; + for (i = 0; i < gm->gm_pf_num; i++) { + pf = &gm->gm_pfs[i]; + kfree(pf->auth_domain_name); + pf->auth_domain_name = NULL; } - memcpy(gm->gm_oid.data, mech_type->data, mech_type->len); - /* We're counting the reference in the registered_mechs list: */ - atomic_set(&gm->gm_count, 1); - gm->gm_ops = ops; - - spin_lock(®istered_mechs_lock); - list_add(&gm->gm_list, ®istered_mechs); - spin_unlock(®istered_mechs_lock); - dprintk("RPC: gss_mech_register: registered mechanism with oid:\n"); - print_hexl((u32 *)mech_type->data, mech_type->len, 0); - return 0; } -/* The following must be called with spinlock held: */ -int -do_gss_mech_unregister(struct gss_api_mech *gm) +static inline char * +make_auth_domain_name(char *name) { + static char *prefix = "gss/"; + char *new; - list_del(&gm->gm_list); + new = kmalloc(strlen(name) + strlen(prefix) + 1, GFP_KERNEL); + if (new) { + strcpy(new, prefix); + strcat(new, name); + } + return new; +} + +static int +gss_mech_svc_setup(struct gss_api_mech *gm) +{ + struct pf_desc *pf; + int i, status; - dprintk("RPC: unregistered mechanism with oid:\n"); - print_hexl((u32 *)gm->gm_oid.data, gm->gm_oid.len, 0); - if (!gss_mech_put(gm)) { - dprintk("RPC: We just unregistered a gss_mechanism which" - " someone is still using.\n"); - return -1; - } else { - return 0; + for (i = 0; i < gm->gm_pf_num; i++) { + pf = &gm->gm_pfs[i]; + pf->auth_domain_name = make_auth_domain_name(pf->name); + status = -ENOMEM; + if (pf->auth_domain_name == NULL) + goto out; + status = svcauth_gss_register_pseudoflavor(pf->pseudoflavor, + pf->auth_domain_name); + if (status) + goto out; } + return 0; +out: + gss_mech_free(gm); + return status; } int -gss_mech_unregister(struct gss_api_mech *gm) +gss_mech_register(struct gss_api_mech *gm) { int status; + status = gss_mech_svc_setup(gm); + if (status) + return status; spin_lock(®istered_mechs_lock); - status = do_gss_mech_unregister(gm); + list_add(&gm->gm_list, ®istered_mechs); spin_unlock(®istered_mechs_lock); - return status; + dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); + return 0; } -int -gss_mech_unregister_all(void) -{ - struct list_head *pos; - struct gss_api_mech *gm; - int status = 0; +EXPORT_SYMBOL(gss_mech_register); +void +gss_mech_unregister(struct gss_api_mech *gm) +{ spin_lock(®istered_mechs_lock); - while (!list_empty(®istered_mechs)) { - pos = registered_mechs.next; - gm = list_entry(pos, struct gss_api_mech, gm_list); - if (do_gss_mech_unregister(gm)) - status = -1; - } + list_del(&gm->gm_list); spin_unlock(®istered_mechs_lock); - return status; + dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); + gss_mech_free(gm); } +EXPORT_SYMBOL(gss_mech_unregister); + struct gss_api_mech * gss_mech_get(struct gss_api_mech *gm) { - atomic_inc(&gm->gm_count); + __module_get(gm->gm_owner); return gm; } +EXPORT_SYMBOL(gss_mech_get); + struct gss_api_mech * -gss_mech_get_by_OID(struct xdr_netobj *mech_type) +gss_mech_get_by_name(const char *name) { - struct gss_api_mech *pos, *gm = NULL; + struct gss_api_mech *pos, *gm = NULL; - dprintk("RPC: gss_mech_get_by_OID searching for mechanism with OID:\n"); - print_hexl((u32 *)mech_type->data, mech_type->len, 0); spin_lock(®istered_mechs_lock); list_for_each_entry(pos, ®istered_mechs, gm_list) { - if ((pos->gm_oid.len == mech_type->len) - && !memcmp(pos->gm_oid.data, mech_type->data, - mech_type->len)) { - gm = gss_mech_get(pos); + if (0 == strcmp(name, pos->gm_name)) { + if (try_module_get(pos->gm_owner)) + gm = pos; break; } } spin_unlock(®istered_mechs_lock); - dprintk("RPC: gss_mech_get_by_OID %s it\n", gm ? "found" : "didn't find"); return gm; + +} + +EXPORT_SYMBOL(gss_mech_get_by_name); + +static inline int +mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) +{ + int i; + + for (i = 0; i < gm->gm_pf_num; i++) { + if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) + return 1; + } + return 0; } struct gss_api_mech * -gss_mech_get_by_name(char *name) +gss_mech_get_by_pseudoflavor(u32 pseudoflavor) { - struct gss_api_mech *pos, *gm = NULL; + struct gss_api_mech *pos, *gm = NULL; spin_lock(®istered_mechs_lock); list_for_each_entry(pos, ®istered_mechs, gm_list) { - if (0 == strcmp(name, pos->gm_ops->name)) { - gm = gss_mech_get(pos); - break; + if (!mech_supports_pseudoflavor(pos, pseudoflavor)) { + module_put(pos->gm_owner); + continue; } + if (try_module_get(pos->gm_owner)) + gm = pos; + break; } spin_unlock(®istered_mechs_lock); return gm; +} + +EXPORT_SYMBOL(gss_mech_get_by_pseudoflavor); +u32 +gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) +{ + int i; + + for (i = 0; i < gm->gm_pf_num; i++) { + if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) + return gm->gm_pfs[i].service; + } + return 0; } -int -gss_mech_put(struct gss_api_mech * gm) +EXPORT_SYMBOL(gss_pseudoflavor_to_service); + +char * +gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) { - if (atomic_dec_and_test(&gm->gm_count)) { - if (gm->gm_oid.len >0) - kfree(gm->gm_oid.data); - kfree(gm); - return 1; - } else { - return 0; + int i; + + for (i = 0; i < gm->gm_pf_num; i++) { + if (gm->gm_pfs[i].service == service) + return gm->gm_pfs[i].auth_domain_name; } + return NULL; } +EXPORT_SYMBOL(gss_service_to_auth_domain_name); + +void +gss_mech_put(struct gss_api_mech * gm) +{ + if (gm) + module_put(gm->gm_owner); +} + +EXPORT_SYMBOL(gss_mech_put); + /* The mech could probably be determined from the token instead, but it's just * as easy for now to pass it in. */ -u32 -gss_import_sec_context(struct xdr_netobj *input_token, +int +gss_import_sec_context(const void *input_token, size_t bufsize, struct gss_api_mech *mech, struct gss_ctx **ctx_id) { - if (!(*ctx_id = kmalloc(sizeof(**ctx_id), GFP_KERNEL))) + if (!(*ctx_id = kzalloc(sizeof(**ctx_id), GFP_KERNEL))) return GSS_S_FAILURE; - memset(*ctx_id, 0, sizeof(**ctx_id)); (*ctx_id)->mech_type = gss_mech_get(mech); return mech->gm_ops - ->gss_import_sec_context(input_token, *ctx_id); + ->gss_import_sec_context(input_token, bufsize, *ctx_id); } /* gss_get_mic: compute a mic over message and return mic_token. */ u32 gss_get_mic(struct gss_ctx *context_handle, - u32 qop, struct xdr_buf *message, struct xdr_netobj *mic_token) { return context_handle->mech_type->gm_ops ->gss_get_mic(context_handle, - qop, message, mic_token); } @@ -227,16 +263,34 @@ gss_get_mic(struct gss_ctx *context_handle, u32 gss_verify_mic(struct gss_ctx *context_handle, struct xdr_buf *message, - struct xdr_netobj *mic_token, - u32 *qstate) + struct xdr_netobj *mic_token) { return context_handle->mech_type->gm_ops ->gss_verify_mic(context_handle, message, - mic_token, - qstate); + mic_token); +} + +u32 +gss_wrap(struct gss_ctx *ctx_id, + int offset, + struct xdr_buf *buf, + struct page **inpages) +{ + return ctx_id->mech_type->gm_ops + ->gss_wrap(ctx_id, offset, buf, inpages); +} + +u32 +gss_unwrap(struct gss_ctx *ctx_id, + int offset, + struct xdr_buf *buf) +{ + return ctx_id->mech_type->gm_ops + ->gss_unwrap(ctx_id, offset, buf); } + /* gss_delete_sec_context: free all resources associated with context_handle. * Note this differs from the RFC 2744-specified prototype in that we don't * bother returning an output token, since it would never be used anyway. */ @@ -244,7 +298,8 @@ gss_verify_mic(struct gss_ctx *context_handle, u32 gss_delete_sec_context(struct gss_ctx **context_handle) { - dprintk("gss_delete_sec_context deleting %p\n",*context_handle); + dprintk("RPC: gss_delete_sec_context deleting %p\n", + *context_handle); if (!*context_handle) return(GSS_S_NO_CONTEXT); @@ -252,8 +307,7 @@ gss_delete_sec_context(struct gss_ctx **context_handle) (*context_handle)->mech_type->gm_ops ->gss_delete_sec_context((*context_handle) ->internal_ctx_id); - if ((*context_handle)->mech_type) - gss_mech_put((*context_handle)->mech_type); + gss_mech_put((*context_handle)->mech_type); kfree(*context_handle); *context_handle=NULL; return GSS_S_COMPLETE;