2 * linux/net/sunrpc/gss_mech_switch.c
4 * Copyright (c) 2001 The Regents of the University of Michigan.
7 * J. Bruce Fields <bfields@umich.edu>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
36 #include <linux/types.h>
37 #include <linux/slab.h>
38 #include <linux/socket.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/gss_err.h>
43 #include <linux/sunrpc/sched.h>
44 #include <linux/sunrpc/gss_api.h>
45 #include <linux/sunrpc/clnt.h>
48 # define RPCDBG_FACILITY RPCDBG_AUTH
51 static LIST_HEAD(registered_mechs);
52 static spinlock_t registered_mechs_lock = SPIN_LOCK_UNLOCKED;
54 /* Reference counting: The reference count includes the reference in the
55 * global registered_mechs list. That reference will never diseappear
56 * (so the reference count will never go below 1) until after the mech
57 * is removed from the list. Nothing can be removed from the list without
58 * first getting the registered_mechs_lock, so a gss_api_mech won't diseappear
59 * from underneath us while we hold the registered_mech_lock. */
62 gss_mech_register(struct xdr_netobj * mech_type, struct gss_api_ops * ops)
64 struct gss_api_mech *gm;
66 if (!(gm = kmalloc(sizeof(*gm), GFP_KERNEL))) {
67 printk("Failed to allocate memory in gss_mech_register");
70 gm->gm_oid.len = mech_type->len;
71 if (!(gm->gm_oid.data = kmalloc(mech_type->len, GFP_KERNEL))) {
73 printk("Failed to allocate memory in gss_mech_register");
76 memcpy(gm->gm_oid.data, mech_type->data, mech_type->len);
77 /* We're counting the reference in the registered_mechs list: */
78 atomic_set(&gm->gm_count, 1);
81 spin_lock(®istered_mechs_lock);
82 list_add(&gm->gm_list, ®istered_mechs);
83 spin_unlock(®istered_mechs_lock);
84 dprintk("RPC: gss_mech_register: registered mechanism with oid:\n");
85 print_hexl((u32 *)mech_type->data, mech_type->len, 0);
89 /* The following must be called with spinlock held: */
91 do_gss_mech_unregister(struct gss_api_mech *gm)
94 list_del(&gm->gm_list);
96 dprintk("RPC: unregistered mechanism with oid:\n");
97 print_hexl((u32 *)gm->gm_oid.data, gm->gm_oid.len, 0);
98 if (!gss_mech_put(gm)) {
99 dprintk("RPC: We just unregistered a gss_mechanism which"
100 " someone is still using.\n");
108 gss_mech_unregister(struct gss_api_mech *gm)
112 spin_lock(®istered_mechs_lock);
113 status = do_gss_mech_unregister(gm);
114 spin_unlock(®istered_mechs_lock);
119 gss_mech_unregister_all(void)
121 struct list_head *pos;
122 struct gss_api_mech *gm;
125 spin_lock(®istered_mechs_lock);
126 while (!list_empty(®istered_mechs)) {
127 pos = registered_mechs.next;
128 gm = list_entry(pos, struct gss_api_mech, gm_list);
129 if (do_gss_mech_unregister(gm))
132 spin_unlock(®istered_mechs_lock);
136 struct gss_api_mech *
137 gss_mech_get(struct gss_api_mech *gm)
139 atomic_inc(&gm->gm_count);
143 struct gss_api_mech *
144 gss_mech_get_by_OID(struct xdr_netobj *mech_type)
146 struct gss_api_mech *pos, *gm = NULL;
148 dprintk("RPC: gss_mech_get_by_OID searching for mechanism with OID:\n");
149 print_hexl((u32 *)mech_type->data, mech_type->len, 0);
150 spin_lock(®istered_mechs_lock);
151 list_for_each_entry(pos, ®istered_mechs, gm_list) {
152 if ((pos->gm_oid.len == mech_type->len)
153 && !memcmp(pos->gm_oid.data, mech_type->data,
155 gm = gss_mech_get(pos);
159 spin_unlock(®istered_mechs_lock);
160 dprintk("RPC: gss_mech_get_by_OID %s it\n", gm ? "found" : "didn't find");
164 struct gss_api_mech *
165 gss_mech_get_by_name(char *name)
167 struct gss_api_mech *pos, *gm = NULL;
169 spin_lock(®istered_mechs_lock);
170 list_for_each_entry(pos, ®istered_mechs, gm_list) {
171 if (0 == strcmp(name, pos->gm_ops->name)) {
172 gm = gss_mech_get(pos);
176 spin_unlock(®istered_mechs_lock);
182 gss_mech_put(struct gss_api_mech * gm)
184 if (atomic_dec_and_test(&gm->gm_count)) {
185 if (gm->gm_oid.len >0)
186 kfree(gm->gm_oid.data);
194 /* The mech could probably be determined from the token instead, but it's just
195 * as easy for now to pass it in. */
197 gss_import_sec_context(struct xdr_netobj *input_token,
198 struct gss_api_mech *mech,
199 struct gss_ctx **ctx_id)
201 if (!(*ctx_id = kmalloc(sizeof(**ctx_id), GFP_KERNEL)))
202 return GSS_S_FAILURE;
203 memset(*ctx_id, 0, sizeof(**ctx_id));
204 (*ctx_id)->mech_type = gss_mech_get(mech);
207 ->gss_import_sec_context(input_token, *ctx_id);
210 /* gss_get_mic: compute a mic over message and return mic_token. */
213 gss_get_mic(struct gss_ctx *context_handle,
215 struct xdr_buf *message,
216 struct xdr_netobj *mic_token)
218 return context_handle->mech_type->gm_ops
219 ->gss_get_mic(context_handle,
225 /* gss_verify_mic: check whether the provided mic_token verifies message. */
228 gss_verify_mic(struct gss_ctx *context_handle,
229 struct xdr_buf *message,
230 struct xdr_netobj *mic_token,
233 return context_handle->mech_type->gm_ops
234 ->gss_verify_mic(context_handle,
240 /* gss_delete_sec_context: free all resources associated with context_handle.
241 * Note this differs from the RFC 2744-specified prototype in that we don't
242 * bother returning an output token, since it would never be used anyway. */
245 gss_delete_sec_context(struct gss_ctx **context_handle)
247 dprintk("gss_delete_sec_context deleting %p\n",*context_handle);
249 if (!*context_handle)
250 return(GSS_S_NO_CONTEXT);
251 if ((*context_handle)->internal_ctx_id != 0)
252 (*context_handle)->mech_type->gm_ops
253 ->gss_delete_sec_context((*context_handle)
255 if ((*context_handle)->mech_type)
256 gss_mech_put((*context_handle)->mech_type);
257 kfree(*context_handle);
258 *context_handle=NULL;
259 return GSS_S_COMPLETE;