patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / net / sunrpc / auth_gss / gss_pseudoflavors.c
1 /*
2  *  linux/net/sunrpc/gss_union.c
3  *
4  *  Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/generic code
5  *
6  *  Copyright (c) 2001 The Regents of the University of Michigan.
7  *  All rights reserved.
8  *
9  *  Andy Adamson   <andros@umich.edu>
10  *
11  */
12
13 /*
14  * Copyright 1993 by OpenVision Technologies, Inc.
15  *
16  * Permission to use, copy, modify, distribute, and sell this software
17  * and its documentation for any purpose is hereby granted without fee,
18  * provided that the above copyright notice appears in all copies and
19  * that both that copyright notice and this permission notice appear in
20  * supporting documentation, and that the name of OpenVision not be used
21  * in advertising or publicity pertaining to distribution of the software
22  * without specific, written prior permission. OpenVision makes no
23  * representations about the suitability of this software for any
24  * purpose.  It is provided "as is" without express or implied warranty.
25  *
26  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
27  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
28  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
29  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
30  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
31  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
32  * PERFORMANCE OF THIS SOFTWARE.
33  */ 
34
35 #include <linux/types.h>
36 #include <linux/slab.h>
37 #include <linux/socket.h>
38 #include <linux/sunrpc/gss_asn1.h>
39 #include <linux/sunrpc/auth_gss.h>
40
41 #ifdef RPC_DEBUG
42 # define RPCDBG_FACILITY        RPCDBG_AUTH
43 #endif
44
45 static LIST_HEAD(registered_triples);
46 static spinlock_t registered_triples_lock = SPIN_LOCK_UNLOCKED;
47
48 /* The following must be called with spinlock held: */
49 static struct sup_sec_triple *
50 do_lookup_triple_by_pseudoflavor(u32 pseudoflavor)
51 {
52         struct sup_sec_triple *pos, *triple = NULL;
53
54         list_for_each_entry(pos, &registered_triples, triples) {
55                 if (pos->pseudoflavor == pseudoflavor) {
56                         triple = pos;
57                         break;
58                 }
59         }
60         return triple;
61 }
62
63 /* XXX Need to think about reference counting of triples and of mechs.
64  * Currently we do no reference counting of triples, and I think that's
65  * probably OK given the reference counting on mechs, but there's probably
66  * a better way to do all this. */
67
68 int
69 gss_register_triple(u32 pseudoflavor, struct gss_api_mech *mech,
70                           u32 qop, u32 service)
71 {
72         struct sup_sec_triple *triple;
73
74         if (!(triple = kmalloc(sizeof(*triple), GFP_KERNEL))) {
75                 printk("Alloc failed in gss_register_triple");
76                 goto err;
77         }
78         triple->pseudoflavor = pseudoflavor;
79         triple->mech = gss_mech_get_by_OID(&mech->gm_oid);
80         triple->qop = qop;
81         triple->service = service;
82
83         spin_lock(&registered_triples_lock);
84         if (do_lookup_triple_by_pseudoflavor(pseudoflavor)) {
85                 printk(KERN_WARNING "RPC: Registered pseudoflavor %d again\n",
86                                 pseudoflavor);
87                 goto err_unlock;
88         }
89         list_add(&triple->triples, &registered_triples);
90         spin_unlock(&registered_triples_lock);
91         dprintk("RPC:      registered pseudoflavor %d\n", pseudoflavor);
92
93         return 0;
94
95 err_unlock:
96         kfree(triple);
97         spin_unlock(&registered_triples_lock);
98 err:
99         return -1;
100 }
101
102 int
103 gss_unregister_triple(u32 pseudoflavor)
104 {
105         struct sup_sec_triple *triple;
106
107         spin_lock(&registered_triples_lock);
108         if (!(triple = do_lookup_triple_by_pseudoflavor(pseudoflavor))) {
109                 spin_unlock(&registered_triples_lock);
110                 printk("Can't unregister unregistered pseudoflavor %d\n",
111                        pseudoflavor);
112                 return -1;
113         }
114         list_del(&triple->triples);
115         spin_unlock(&registered_triples_lock);
116         gss_mech_put(triple->mech);
117         kfree(triple);
118         return 0;
119
120 }
121
122 void
123 print_sec_triple(struct xdr_netobj *oid,u32 qop,u32 service)
124 {
125         dprintk("RPC: print_sec_triple:\n");
126         dprintk("                     oid_len %d\n  oid :\n",oid->len);
127         print_hexl((u32 *)oid->data,oid->len,0);
128         dprintk("                     qop %d\n",qop);
129         dprintk("                     service %d\n",service);
130 }
131
132 /* Function: gss_get_cmp_triples
133  *
134  * Description: search sec_triples for a matching security triple
135  * return pseudoflavor if match, else 0
136  * (Note that 0 is a valid pseudoflavor, but not for any gss pseudoflavor
137  * (0 means auth_null), so this shouldn't cause confusion.)
138  */
139 u32
140 gss_cmp_triples(u32 oid_len, char *oid_data, u32 qop, u32 service)
141 {
142         struct sup_sec_triple *triple;
143         u32 pseudoflavor = 0;
144         struct xdr_netobj oid;
145
146         oid.len = oid_len;
147         oid.data = oid_data;
148
149         dprintk("RPC:      gss_cmp_triples\n");
150         print_sec_triple(&oid,qop,service);
151
152         spin_lock(&registered_triples_lock);
153         list_for_each_entry(triple, &registered_triples, triples) {
154                 if((g_OID_equal(&oid, &triple->mech->gm_oid))
155                     && (qop == triple->qop)
156                     && (service == triple->service)) {
157                         pseudoflavor = triple->pseudoflavor;
158                         break;
159                 }
160         }
161         spin_unlock(&registered_triples_lock);
162         dprintk("RPC:      gss_cmp_triples return %d\n", pseudoflavor);
163         return pseudoflavor;
164 }
165
166 u32
167 gss_get_pseudoflavor(struct gss_ctx *ctx, u32 qop, u32 service)
168 {
169         return gss_cmp_triples(ctx->mech_type->gm_oid.len,
170                                ctx->mech_type->gm_oid.data,
171                                qop, service);
172 }
173
174 /* Returns nonzero iff the given pseudoflavor is in the supported list.
175  * (Note that without incrementing a reference count or anything, this
176  * doesn't give any guarantees.) */
177 int
178 gss_pseudoflavor_supported(u32 pseudoflavor)
179 {
180         struct sup_sec_triple *triple;
181
182         spin_lock(&registered_triples_lock);
183         triple = do_lookup_triple_by_pseudoflavor(pseudoflavor);
184         spin_unlock(&registered_triples_lock);
185         return (triple ? 1 : 0);
186 }
187
188 u32
189 gss_pseudoflavor_to_service(u32 pseudoflavor)
190 {
191         struct sup_sec_triple *triple;
192
193         spin_lock(&registered_triples_lock);
194         triple = do_lookup_triple_by_pseudoflavor(pseudoflavor);
195         spin_unlock(&registered_triples_lock);
196         if (!triple) {
197                 dprintk("RPC:      gss_pseudoflavor_to_service called with unsupported pseudoflavor %d\n",
198                                 pseudoflavor);
199                 return 0;
200         }
201         return triple->service;
202 }
203
204 struct gss_api_mech *
205 gss_pseudoflavor_to_mech(u32 pseudoflavor) {
206         struct sup_sec_triple *triple;
207         struct gss_api_mech *mech = NULL;
208
209         spin_lock(&registered_triples_lock);
210         triple = do_lookup_triple_by_pseudoflavor(pseudoflavor);
211         spin_unlock(&registered_triples_lock);
212         if (triple)
213                 mech = gss_mech_get(triple->mech);
214         else
215                 dprintk("RPC:      gss_pseudoflavor_to_mech called with unsupported pseudoflavor %d\n",
216                                 pseudoflavor);
217         return mech;
218 }
219
220 int
221 gss_pseudoflavor_to_mechOID(u32 pseudoflavor, struct xdr_netobj * oid)
222 {
223         struct gss_api_mech *mech;
224
225         mech = gss_pseudoflavor_to_mech(pseudoflavor);
226         if (!mech)  {
227                 dprintk("RPC:      gss_pseudoflavor_to_mechOID called with unsupported pseudoflavor %d\n",
228                                 pseudoflavor);
229                         return -1;
230         }
231         oid->len = mech->gm_oid.len;
232         if (!(oid->data = kmalloc(oid->len, GFP_KERNEL)))
233                 return -1;
234         memcpy(oid->data, mech->gm_oid.data, oid->len);
235         gss_mech_put(mech);
236         return 0;
237 }