Whamcloud - gitweb
b=6394
[fs/lustre-release.git] / lustre / sec / gss / gss_mech_switch.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Modifications for Lustre
5  * Copyright 2004, Cluster File Systems, Inc.
6  * All rights reserved
7  * Author: Eric Mei <ericm@clusterfs.com>
8  */
9
10 /*
11  *  linux/net/sunrpc/gss_mech_switch.c
12  *
13  *  Copyright (c) 2001 The Regents of the University of Michigan.
14  *  All rights reserved.
15  *
16  *  J. Bruce Fields   <bfields@umich.edu>
17  *
18  *  Redistribution and use in source and binary forms, with or without
19  *  modification, are permitted provided that the following conditions
20  *  are met:
21  *
22  *  1. Redistributions of source code must retain the above copyright
23  *     notice, this list of conditions and the following disclaimer.
24  *  2. Redistributions in binary form must reproduce the above copyright
25  *     notice, this list of conditions and the following disclaimer in the
26  *     documentation and/or other materials provided with the distribution.
27  *  3. Neither the name of the University nor the names of its
28  *     contributors may be used to endorse or promote products derived
29  *     from this software without specific prior written permission.
30  *
31  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
32  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
33  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
35  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
38  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
39  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  *
43  */
44
45 #ifndef EXPORT_SYMTAB
46 # define EXPORT_SYMTAB
47 #endif
48 #define DEBUG_SUBSYSTEM S_SEC
49 #ifdef __KERNEL__
50 #include <linux/init.h>
51 #include <linux/module.h>
52 #include <linux/slab.h>
53 #else
54 #include <liblustre.h>
55 #endif
56
57 #include <libcfs/kp30.h>
58 #include <linux/obd.h>
59 #include <linux/obd_class.h>
60 #include <linux/obd_support.h>
61 #include <linux/lustre_idl.h>
62 #include <linux/lustre_net.h>
63 #include <linux/lustre_import.h>
64 #include <linux/lustre_sec.h>
65
66 #include "gss_err.h"
67 #include "gss_internal.h"
68 #include "gss_api.h"
69
70 static LIST_HEAD(registered_mechs);
71 static spinlock_t registered_mechs_lock = SPIN_LOCK_UNLOCKED;
72
73 int
74 kgss_mech_register(struct gss_api_mech *gm)
75 {
76         spin_lock(&registered_mechs_lock);
77         list_add(&gm->gm_list, &registered_mechs);
78         spin_unlock(&registered_mechs_lock);
79         CWARN("registered gss mechanism %s\n", gm->gm_name);
80         return 0;
81 }
82
83 //EXPORT_SYMBOL(kgss_mech_register);
84
85 void
86 kgss_mech_unregister(struct gss_api_mech *gm)
87 {
88         spin_lock(&registered_mechs_lock);
89         list_del(&gm->gm_list);
90         spin_unlock(&registered_mechs_lock);
91         CWARN("unregistered gss mechanism %s\n", gm->gm_name);
92 //        gss_mech_free(gm);
93 }
94
95 //EXPORT_SYMBOL(gss_mech_unregister);
96
97 struct gss_api_mech *
98 kgss_mech_get(struct gss_api_mech *gm)
99 {
100         __module_get(gm->gm_owner);
101         return gm;
102 }
103
104 //EXPORT_SYMBOL(kgss_mech_get);
105
106 struct gss_api_mech *
107 kgss_name_to_mech(char *name)
108 {
109         struct gss_api_mech *pos, *gm = NULL;
110
111         spin_lock(&registered_mechs_lock);
112         list_for_each_entry(pos, &registered_mechs, gm_list) {
113                 if (0 == strcmp(name, pos->gm_name)) {
114                         if (!try_module_get(pos->gm_owner))
115                                 continue;
116                         gm = pos;
117                         break;
118                 }
119         }
120         spin_unlock(&registered_mechs_lock);
121         return gm;
122
123 }
124
125 //EXPORT_SYMBOL(gss_name_to_mech);
126
127 static inline int
128 mech_supports_subflavor(struct gss_api_mech *gm, __u32 subflavor)
129 {
130         int i;
131
132         for (i = 0; i < gm->gm_sf_num; i++) {
133                 if (gm->gm_sfs[i].subflavor == subflavor)
134                         return 1;
135         }
136         return 0;
137 }
138
139 struct gss_api_mech *
140 kgss_subflavor_to_mech(__u32 subflavor)
141 {
142         struct gss_api_mech *pos, *gm = NULL;
143
144         spin_lock(&registered_mechs_lock);
145         list_for_each_entry(pos, &registered_mechs, gm_list) {
146                 if (!try_module_get(pos->gm_owner))
147                         continue;
148                 if (!mech_supports_subflavor(pos, subflavor)) {
149                         module_put(pos->gm_owner);
150                         continue;
151                 }
152                 gm = pos;
153                 break;
154         }
155         spin_unlock(&registered_mechs_lock);
156         return gm;
157 }
158
159 //EXPORT_SYMBOL(gss_subflavor_to_mech);
160
161 void
162 kgss_mech_put(struct gss_api_mech *gm)
163 {
164         module_put(gm->gm_owner);
165 }
166
167 //EXPORT_SYMBOL(kgss_mech_put);
168
169 /* The mech could probably be determined from the token instead, but it's just
170  * as easy for now to pass it in. */
171 __u32
172 kgss_import_sec_context(rawobj_t                *input_token,
173                         struct gss_api_mech     *mech,
174                         struct gss_ctx         **ctx_id)
175 {
176         OBD_ALLOC(*ctx_id, sizeof(**ctx_id));
177         if (*ctx_id == NULL)
178                 return GSS_S_FAILURE;
179
180         (*ctx_id)->mech_type = kgss_mech_get(mech);
181
182         LASSERT(mech);
183         LASSERT(mech->gm_ops);
184         LASSERT(mech->gm_ops->gss_import_sec_context);
185         return mech->gm_ops->gss_import_sec_context(input_token, *ctx_id);
186 }
187
188 /*
189  * this interface is much simplified, currently we only need endtime.
190  */
191 __u32
192 kgss_inquire_context(struct gss_ctx    *context_handle,
193                      __u64             *endtime)
194 {
195         LASSERT(context_handle);
196         LASSERT(context_handle->mech_type);
197         LASSERT(context_handle->mech_type->gm_ops);
198         LASSERT(context_handle->mech_type->gm_ops->gss_inquire_context);
199
200         return context_handle->mech_type->gm_ops
201                 ->gss_inquire_context(context_handle,
202                                       endtime);
203 }
204
205 /* gss_get_mic: compute a mic over message and return mic_token. */
206 __u32
207 kgss_get_mic(struct gss_ctx     *context_handle,
208              __u32               qop,
209              rawobj_t           *message,
210              rawobj_t           *mic_token)
211 {
212         LASSERT(context_handle);
213         LASSERT(context_handle->mech_type);
214         LASSERT(context_handle->mech_type->gm_ops);
215         LASSERT(context_handle->mech_type->gm_ops->gss_get_mic);
216
217         return context_handle->mech_type->gm_ops
218                 ->gss_get_mic(context_handle,
219                               qop,
220                               message,
221                               mic_token);
222 }
223
224 /* gss_verify_mic: check whether the provided mic_token verifies message. */
225 __u32
226 kgss_verify_mic(struct gss_ctx  *context_handle,
227                 rawobj_t        *message,
228                 rawobj_t        *mic_token,
229                 __u32           *qstate)
230 {
231         LASSERT(context_handle);
232         LASSERT(context_handle->mech_type);
233         LASSERT(context_handle->mech_type->gm_ops);
234         LASSERT(context_handle->mech_type->gm_ops->gss_verify_mic);
235
236         return context_handle->mech_type->gm_ops
237                 ->gss_verify_mic(context_handle,
238                                  message,
239                                  mic_token,
240                                  qstate);
241 }
242
243 __u32
244 kgss_wrap(struct gss_ctx        *context_handle,
245           __u32                  qop,
246           rawobj_buf_t          *inbuf,
247           rawobj_t              *outbuf)
248 {
249         LASSERT(context_handle);
250         LASSERT(context_handle->mech_type);
251         LASSERT(context_handle->mech_type->gm_ops);
252         LASSERT(context_handle->mech_type->gm_ops->gss_wrap);
253
254         return context_handle->mech_type->gm_ops
255                 ->gss_wrap(context_handle, qop, inbuf, outbuf);
256 }
257
258 __u32
259 kgss_unwrap(struct gss_ctx        *context_handle,
260             __u32                  qop,
261             rawobj_t              *inbuf,
262             rawobj_t              *outbuf)
263 {
264         LASSERT(context_handle);
265         LASSERT(context_handle->mech_type);
266         LASSERT(context_handle->mech_type->gm_ops);
267         LASSERT(context_handle->mech_type->gm_ops->gss_unwrap);
268
269         return context_handle->mech_type->gm_ops
270                 ->gss_unwrap(context_handle, qop, inbuf, outbuf);
271 }
272
273
274 /* gss_delete_sec_context: free all resources associated with context_handle.
275  * Note this differs from the RFC 2744-specified prototype in that we don't
276  * bother returning an output token, since it would never be used anyway. */
277
278 __u32
279 kgss_delete_sec_context(struct gss_ctx  **context_handle)
280 {
281         struct gss_api_mech *mech;
282
283         CDEBUG(D_SEC, "deleting %p\n", *context_handle);
284
285         if (!*context_handle)
286                 return(GSS_S_NO_CONTEXT);
287
288         mech = (*context_handle)->mech_type;
289         if ((*context_handle)->internal_ctx_id != 0) {
290                 LASSERT(mech);
291                 LASSERT(mech->gm_ops);
292                 LASSERT(mech->gm_ops->gss_delete_sec_context);
293                 mech->gm_ops->gss_delete_sec_context(
294                                         (*context_handle)->internal_ctx_id);
295         }
296         if (mech)
297                 kgss_mech_put(mech);
298
299         OBD_FREE(*context_handle, sizeof(**context_handle));
300         *context_handle=NULL;
301         return GSS_S_COMPLETE;
302 }