Whamcloud - gitweb
4e2b17ef0463e21049c221ab2695c1d09f031e1d
[fs/lustre-release.git] / lustre / ptlrpc / 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 - 2006, 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 <obd.h>
58 #include <obd_class.h>
59 #include <obd_support.h>
60 #include <lustre/lustre_idl.h>
61 #include <lustre_net.h>
62 #include <lustre_import.h>
63 #include <lustre_sec.h>
64
65 #include "gss_err.h"
66 #include "gss_internal.h"
67 #include "gss_api.h"
68
69 static LIST_HEAD(registered_mechs);
70 static spinlock_t registered_mechs_lock = SPIN_LOCK_UNLOCKED;
71
72 int lgss_mech_register(struct gss_api_mech *gm)
73 {
74         spin_lock(&registered_mechs_lock);
75         list_add(&gm->gm_list, &registered_mechs);
76         spin_unlock(&registered_mechs_lock);
77         CWARN("Register %s mechanism\n", gm->gm_name);
78         return 0;
79 }
80
81 void lgss_mech_unregister(struct gss_api_mech *gm)
82 {
83         spin_lock(&registered_mechs_lock);
84         list_del(&gm->gm_list);
85         spin_unlock(&registered_mechs_lock);
86         CWARN("Unregister %s mechanism\n", gm->gm_name);
87 }
88
89
90 struct gss_api_mech *lgss_mech_get(struct gss_api_mech *gm)
91 {
92         __module_get(gm->gm_owner);
93         return gm;
94 }
95
96 struct gss_api_mech *lgss_name_to_mech(char *name)
97 {
98         struct gss_api_mech *pos, *gm = NULL;
99
100         spin_lock(&registered_mechs_lock);
101         list_for_each_entry(pos, &registered_mechs, gm_list) {
102                 if (0 == strcmp(name, pos->gm_name)) {
103                         if (!try_module_get(pos->gm_owner))
104                                 continue;
105                         gm = pos;
106                         break;
107                 }
108         }
109         spin_unlock(&registered_mechs_lock);
110         return gm;
111
112 }
113
114 static inline
115 int mech_supports_subflavor(struct gss_api_mech *gm, __u32 subflavor)
116 {
117         int i;
118
119         for (i = 0; i < gm->gm_sf_num; i++) {
120                 if (gm->gm_sfs[i].sf_subflavor == subflavor)
121                         return 1;
122         }
123         return 0;
124 }
125
126 struct gss_api_mech *lgss_subflavor_to_mech(__u32 subflavor)
127 {
128         struct gss_api_mech *pos, *gm = NULL;
129
130         spin_lock(&registered_mechs_lock);
131         list_for_each_entry(pos, &registered_mechs, gm_list) {
132                 if (!try_module_get(pos->gm_owner))
133                         continue;
134                 if (!mech_supports_subflavor(pos, subflavor)) {
135                         module_put(pos->gm_owner);
136                         continue;
137                 }
138                 gm = pos;
139                 break;
140         }
141         spin_unlock(&registered_mechs_lock);
142         return gm;
143 }
144
145 void lgss_mech_put(struct gss_api_mech *gm)
146 {
147         module_put(gm->gm_owner);
148 }
149
150 /* The mech could probably be determined from the token instead, but it's just
151  * as easy for now to pass it in. */
152 __u32 lgss_import_sec_context(rawobj_t *input_token,
153                               struct gss_api_mech *mech,
154                               struct gss_ctx **ctx_id)
155 {
156         OBD_ALLOC_PTR(*ctx_id);
157         if (*ctx_id == NULL)
158                 return GSS_S_FAILURE;
159
160         (*ctx_id)->mech_type = lgss_mech_get(mech);
161
162         LASSERT(mech);
163         LASSERT(mech->gm_ops);
164         LASSERT(mech->gm_ops->gss_import_sec_context);
165         return mech->gm_ops->gss_import_sec_context(input_token, *ctx_id);
166 }
167
168 __u32 lgss_copy_reverse_context(struct gss_ctx *ctx_id,
169                                 struct gss_ctx **ctx_id_new)
170 {
171         struct gss_api_mech *mech = ctx_id->mech_type;
172         __u32                major;
173
174         LASSERT(mech);
175
176         OBD_ALLOC_PTR(*ctx_id_new);
177         if (*ctx_id_new == NULL)
178                 return GSS_S_FAILURE;
179
180         (*ctx_id_new)->mech_type = lgss_mech_get(mech);
181
182         LASSERT(mech);
183         LASSERT(mech->gm_ops);
184         LASSERT(mech->gm_ops->gss_copy_reverse_context);
185
186         major = mech->gm_ops->gss_copy_reverse_context(ctx_id, *ctx_id_new);
187         if (major != GSS_S_COMPLETE) {
188                 lgss_mech_put(mech);
189                 OBD_FREE_PTR(*ctx_id_new);
190                 *ctx_id_new = NULL;
191         }
192         return major;
193 }
194
195 /*
196  * this interface is much simplified, currently we only need endtime.
197  */
198 __u32 lgss_inquire_context(struct gss_ctx *context_handle,
199                            unsigned long  *endtime)
200 {
201         LASSERT(context_handle);
202         LASSERT(context_handle->mech_type);
203         LASSERT(context_handle->mech_type->gm_ops);
204         LASSERT(context_handle->mech_type->gm_ops->gss_inquire_context);
205
206         return context_handle->mech_type->gm_ops
207                 ->gss_inquire_context(context_handle,
208                                       endtime);
209 }
210
211 /* gss_get_mic: compute a mic over message and return mic_token. */
212 __u32 lgss_get_mic(struct gss_ctx *context_handle,
213                    int msgcnt,
214                    rawobj_t *msg,
215                    rawobj_t *mic_token)
216 {
217         LASSERT(context_handle);
218         LASSERT(context_handle->mech_type);
219         LASSERT(context_handle->mech_type->gm_ops);
220         LASSERT(context_handle->mech_type->gm_ops->gss_get_mic);
221
222         return context_handle->mech_type->gm_ops
223                 ->gss_get_mic(context_handle,
224                               msgcnt,
225                               msg,
226                               mic_token);
227 }
228
229 /* gss_verify_mic: check whether the provided mic_token verifies message. */
230 __u32 lgss_verify_mic(struct gss_ctx *context_handle,
231                       int msgcnt,
232                       rawobj_t *msg,
233                       rawobj_t *mic_token)
234 {
235         LASSERT(context_handle);
236         LASSERT(context_handle->mech_type);
237         LASSERT(context_handle->mech_type->gm_ops);
238         LASSERT(context_handle->mech_type->gm_ops->gss_verify_mic);
239
240         return context_handle->mech_type->gm_ops
241                 ->gss_verify_mic(context_handle,
242                                  msgcnt,
243                                  msg,
244                                  mic_token);
245 }
246
247 #if 0
248 __u32 lgss_wrap(struct gss_ctx *context_handle,
249                 __u32 qop,
250                 rawobj_buf_t *inbuf,
251                 rawobj_t *outbuf)
252 {
253         LASSERT(context_handle);
254         LASSERT(context_handle->mech_type);
255         LASSERT(context_handle->mech_type->gm_ops);
256         LASSERT(context_handle->mech_type->gm_ops->gss_wrap);
257
258         return context_handle->mech_type->gm_ops
259                 ->gss_wrap(context_handle, qop, inbuf, outbuf);
260 }
261 #endif
262
263 __u32 lgss_wrap(struct gss_ctx *context_handle,
264                 rawobj_t *msg,
265                 int msg_buflen,
266                 rawobj_t *out_token)
267 {
268         LASSERT(context_handle);
269         LASSERT(context_handle->mech_type);
270         LASSERT(context_handle->mech_type->gm_ops);
271         LASSERT(context_handle->mech_type->gm_ops->gss_wrap);
272
273         return context_handle->mech_type->gm_ops
274                 ->gss_wrap(context_handle, msg, msg_buflen, out_token);
275 }
276
277 __u32 lgss_unwrap(struct gss_ctx *context_handle,
278                   rawobj_t *token,
279                   rawobj_t *out_msg)
280 {
281         LASSERT(context_handle);
282         LASSERT(context_handle->mech_type);
283         LASSERT(context_handle->mech_type->gm_ops);
284         LASSERT(context_handle->mech_type->gm_ops->gss_unwrap);
285
286         return context_handle->mech_type->gm_ops
287                 ->gss_unwrap(context_handle, token, out_msg);
288 }
289
290
291 __u32 lgss_plain_encrypt(struct gss_ctx *ctx,
292                          int length,
293                          void *in_buf,
294                          void *out_buf)
295 {
296         LASSERT(ctx);
297         LASSERT(ctx->mech_type);
298         LASSERT(ctx->mech_type->gm_ops);
299         LASSERT(ctx->mech_type->gm_ops->gss_plain_encrypt);
300
301         return ctx->mech_type->gm_ops
302                 ->gss_plain_encrypt(ctx, length, in_buf, out_buf);
303 }
304
305 /* gss_delete_sec_context: free all resources associated with context_handle.
306  * Note this differs from the RFC 2744-specified prototype in that we don't
307  * bother returning an output token, since it would never be used anyway. */
308
309 __u32 lgss_delete_sec_context(struct gss_ctx **context_handle)
310 {
311         struct gss_api_mech *mech;
312
313         CDEBUG(D_SEC, "deleting %p\n", *context_handle);
314
315         if (!*context_handle)
316                 return(GSS_S_NO_CONTEXT);
317
318         mech = (*context_handle)->mech_type;
319         if ((*context_handle)->internal_ctx_id != 0) {
320                 LASSERT(mech);
321                 LASSERT(mech->gm_ops);
322                 LASSERT(mech->gm_ops->gss_delete_sec_context);
323                 mech->gm_ops->gss_delete_sec_context(
324                                         (*context_handle)->internal_ctx_id);
325         }
326         if (mech)
327                 lgss_mech_put(mech);
328
329         OBD_FREE_PTR(*context_handle);
330         *context_handle=NULL;
331         return GSS_S_COMPLETE;
332 }
333
334 int lgss_display(struct gss_ctx *ctx,
335                  char           *buf,
336                  int             bufsize)
337 {
338         LASSERT(ctx);
339         LASSERT(ctx->mech_type);
340         LASSERT(ctx->mech_type->gm_ops);
341         LASSERT(ctx->mech_type->gm_ops->gss_display);
342
343         return ctx->mech_type->gm_ops->gss_display(ctx, buf, bufsize);
344 }