ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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("Registered pseudoflavor %d again\n", pseudoflavor);
86                 goto err_unlock;
87         }
88         list_add(&triple->triples, &registered_triples);
89         spin_unlock(&registered_triples_lock);
90         dprintk("RPC: registered pseudoflavor %d\n", pseudoflavor);
91
92         return 0;
93
94 err_unlock:
95         kfree(triple);
96         spin_unlock(&registered_triples_lock);
97 err:
98         return -1;
99 }
100
101 int
102 gss_unregister_triple(u32 pseudoflavor)
103 {
104         struct sup_sec_triple *triple;
105
106         spin_lock(&registered_triples_lock);
107         if (!(triple = do_lookup_triple_by_pseudoflavor(pseudoflavor))) {
108                 spin_unlock(&registered_triples_lock);
109                 printk("Can't unregister unregistered pseudoflavor %d\n",
110                        pseudoflavor);
111                 return -1;
112         }
113         list_del(&triple->triples);
114         spin_unlock(&registered_triples_lock);
115         gss_mech_put(triple->mech);
116         kfree(triple);
117         return 0;
118
119 }
120
121 void
122 print_sec_triple(struct xdr_netobj *oid,u32 qop,u32 service)
123 {
124         dprintk("RPC: print_sec_triple:\n");
125         dprintk("                     oid_len %d\n  oid :\n",oid->len);
126         print_hexl((u32 *)oid->data,oid->len,0);
127         dprintk("                     qop %d\n",qop);
128         dprintk("                     service %d\n",service);
129 }
130
131 /* Function: gss_get_cmp_triples
132  *
133  * Description: search sec_triples for a matching security triple
134  * return pseudoflavor if match, else 0
135  * (Note that 0 is a valid pseudoflavor, but not for any gss pseudoflavor
136  * (0 means auth_null), so this shouldn't cause confusion.)
137  */
138 u32
139 gss_cmp_triples(u32 oid_len, char *oid_data, u32 qop, u32 service)
140 {
141         struct sup_sec_triple *triple;
142         u32 pseudoflavor = 0;
143         struct xdr_netobj oid;
144
145         oid.len = oid_len;
146         oid.data = oid_data;
147
148         dprintk("RPC: gss_cmp_triples \n");
149         print_sec_triple(&oid,qop,service);
150
151         spin_lock(&registered_triples_lock);
152         list_for_each_entry(triple, &registered_triples, triples) {
153                 if((g_OID_equal(&oid, &triple->mech->gm_oid))
154                     && (qop == triple->qop)
155                     && (service == triple->service)) {
156                         pseudoflavor = triple->pseudoflavor;
157                         break;
158                 }
159         }
160         spin_unlock(&registered_triples_lock);
161         dprintk("RPC: gss_cmp_triples return %d\n", pseudoflavor);
162         return pseudoflavor;
163 }
164
165 u32
166 gss_get_pseudoflavor(struct gss_ctx *ctx, u32 qop, u32 service)
167 {
168         return gss_cmp_triples(ctx->mech_type->gm_oid.len,
169                                ctx->mech_type->gm_oid.data,
170                                qop, service);
171 }
172
173 /* Returns nonzero iff the given pseudoflavor is in the supported list.
174  * (Note that without incrementing a reference count or anything, this
175  * doesn't give any guarantees.) */
176 int
177 gss_pseudoflavor_supported(u32 pseudoflavor)
178 {
179         struct sup_sec_triple *triple;
180
181         spin_lock(&registered_triples_lock);
182         triple = do_lookup_triple_by_pseudoflavor(pseudoflavor);
183         spin_unlock(&registered_triples_lock);
184         return (triple ? 1 : 0);
185 }
186
187 u32
188 gss_pseudoflavor_to_service(u32 pseudoflavor)
189 {
190         struct sup_sec_triple *triple;
191
192         spin_lock(&registered_triples_lock);
193         triple = do_lookup_triple_by_pseudoflavor(pseudoflavor);
194         spin_unlock(&registered_triples_lock);
195         if (!triple) {
196                 dprintk("RPC: gss_pseudoflavor_to_service called with"
197                         " unsupported pseudoflavor %d\n", pseudoflavor);
198                 return 0;
199         }
200         return triple->service;
201 }
202
203 struct gss_api_mech *
204 gss_pseudoflavor_to_mech(u32 pseudoflavor) {
205         struct sup_sec_triple *triple;
206         struct gss_api_mech *mech = NULL;
207
208         spin_lock(&registered_triples_lock);
209         triple = do_lookup_triple_by_pseudoflavor(pseudoflavor);
210         spin_unlock(&registered_triples_lock);
211         if (triple)
212                 mech = gss_mech_get(triple->mech);
213         else
214                 dprintk("RPC: gss_pseudoflavor_to_mech called with"
215                         " unsupported pseudoflavor %d\n", pseudoflavor);
216         return mech;
217 }
218
219 int
220 gss_pseudoflavor_to_mechOID(u32 pseudoflavor, struct xdr_netobj * oid)
221 {
222         struct gss_api_mech *mech;
223
224         mech = gss_pseudoflavor_to_mech(pseudoflavor);
225         if (!mech)  {
226                 dprintk("RPC: gss_pseudoflavor_to_mechOID called with"
227                         " unsupported pseudoflavor %d\n", pseudoflavor);
228                         return -1;
229         }
230         oid->len = mech->gm_oid.len;
231         if (!(oid->data = kmalloc(oid->len, GFP_KERNEL)))
232                 return -1;
233         memcpy(oid->data, mech->gm_oid.data, oid->len);
234         gss_mech_put(mech);
235         return 0;
236 }