Whamcloud - gitweb
608aa8cbd8d26587ebd9f454728fd4d3664be18d
[fs/lustre-release.git] / lustre / ptlrpc / gss / gss_mech_switch.c
1 /*
2  * Modifications for Lustre
3  *
4  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5  *
6  * Copyright (c) 2012, Intel Corporation.
7  *
8  * Author: Eric Mei <ericm@clusterfs.com>
9  */
10
11 /*
12  *  linux/net/sunrpc/gss_mech_switch.c
13  *
14  *  Copyright (c) 2001 The Regents of the University of Michigan.
15  *  All rights reserved.
16  *
17  *  J. Bruce Fields   <bfields@umich.edu>
18  *
19  *  Redistribution and use in source and binary forms, with or without
20  *  modification, are permitted provided that the following conditions
21  *  are met:
22  *
23  *  1. Redistributions of source code must retain the above copyright
24  *     notice, this list of conditions and the following disclaimer.
25  *  2. Redistributions in binary form must reproduce the above copyright
26  *     notice, this list of conditions and the following disclaimer in the
27  *     documentation and/or other materials provided with the distribution.
28  *  3. Neither the name of the University nor the names of its
29  *     contributors may be used to endorse or promote products derived
30  *     from this software without specific prior written permission.
31  *
32  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
33  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
34  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
39  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
40  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
41  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43  *
44  */
45
46 #define DEBUG_SUBSYSTEM S_SEC
47 #ifdef __KERNEL__
48 #include <linux/init.h>
49 #include <linux/module.h>
50 #include <linux/slab.h>
51 #include <linux/mutex.h>
52 #else
53 #include <liblustre.h>
54 #endif
55
56 #include <obd.h>
57 #include <obd_class.h>
58 #include <obd_support.h>
59 #include <lustre/lustre_idl.h>
60 #include <lustre_net.h>
61 #include <lustre_import.h>
62 #include <lustre_sec.h>
63
64 #include "gss_err.h"
65 #include "gss_internal.h"
66 #include "gss_api.h"
67
68 static struct list_head registered_mechs = LIST_HEAD_INIT(registered_mechs);
69 static DEFINE_SPINLOCK(registered_mechs_lock);
70
71 int lgss_mech_register(struct gss_api_mech *gm)
72 {
73         spin_lock(&registered_mechs_lock);
74         list_add(&gm->gm_list, &registered_mechs);
75         spin_unlock(&registered_mechs_lock);
76         CWARN("Register %s mechanism\n", gm->gm_name);
77         return 0;
78 }
79
80 void lgss_mech_unregister(struct gss_api_mech *gm)
81 {
82         spin_lock(&registered_mechs_lock);
83         list_del(&gm->gm_list);
84         spin_unlock(&registered_mechs_lock);
85         CWARN("Unregister %s mechanism\n", gm->gm_name);
86 }
87
88
89 struct gss_api_mech *lgss_mech_get(struct gss_api_mech *gm)
90 {
91         __module_get(gm->gm_owner);
92         return gm;
93 }
94
95 struct gss_api_mech *lgss_name_to_mech(char *name)
96 {
97         struct gss_api_mech *pos, *gm = NULL;
98
99         spin_lock(&registered_mechs_lock);
100         list_for_each_entry(pos, &registered_mechs, gm_list) {
101                 if (0 == strcmp(name, pos->gm_name)) {
102                         if (!try_module_get(pos->gm_owner))
103                                 continue;
104                         gm = pos;
105                         break;
106                 }
107         }
108         spin_unlock(&registered_mechs_lock);
109         return gm;
110
111 }
112
113 static inline
114 int mech_supports_subflavor(struct gss_api_mech *gm, __u32 subflavor)
115 {
116         int i;
117
118         for (i = 0; i < gm->gm_sf_num; i++) {
119                 if (gm->gm_sfs[i].sf_subflavor == subflavor)
120                         return 1;
121         }
122         return 0;
123 }
124
125 struct gss_api_mech *lgss_subflavor_to_mech(__u32 subflavor)
126 {
127         struct gss_api_mech *pos, *gm = NULL;
128
129         spin_lock(&registered_mechs_lock);
130         list_for_each_entry(pos, &registered_mechs, gm_list) {
131                 if (!try_module_get(pos->gm_owner))
132                         continue;
133                 if (!mech_supports_subflavor(pos, subflavor)) {
134                         module_put(pos->gm_owner);
135                         continue;
136                 }
137                 gm = pos;
138                 break;
139         }
140         spin_unlock(&registered_mechs_lock);
141         return gm;
142 }
143
144 void lgss_mech_put(struct gss_api_mech *gm)
145 {
146         module_put(gm->gm_owner);
147 }
148
149 /* The mech could probably be determined from the token instead, but it's just
150  * as easy for now to pass it in. */
151 __u32 lgss_import_sec_context(rawobj_t *input_token,
152                               struct gss_api_mech *mech,
153                               struct gss_ctx **ctx_id)
154 {
155         OBD_ALLOC_PTR(*ctx_id);
156         if (*ctx_id == NULL)
157                 return GSS_S_FAILURE;
158
159         (*ctx_id)->mech_type = lgss_mech_get(mech);
160
161         LASSERT(mech);
162         LASSERT(mech->gm_ops);
163         LASSERT(mech->gm_ops->gss_import_sec_context);
164         return mech->gm_ops->gss_import_sec_context(input_token, *ctx_id);
165 }
166
167 __u32 lgss_copy_reverse_context(struct gss_ctx *ctx_id,
168                                 struct gss_ctx **ctx_id_new)
169 {
170         struct gss_api_mech *mech = ctx_id->mech_type;
171         __u32                major;
172
173         LASSERT(mech);
174
175         OBD_ALLOC_PTR(*ctx_id_new);
176         if (*ctx_id_new == NULL)
177                 return GSS_S_FAILURE;
178
179         (*ctx_id_new)->mech_type = lgss_mech_get(mech);
180
181         LASSERT(mech);
182         LASSERT(mech->gm_ops);
183         LASSERT(mech->gm_ops->gss_copy_reverse_context);
184
185         major = mech->gm_ops->gss_copy_reverse_context(ctx_id, *ctx_id_new);
186         if (major != GSS_S_COMPLETE) {
187                 lgss_mech_put(mech);
188                 OBD_FREE_PTR(*ctx_id_new);
189                 *ctx_id_new = NULL;
190         }
191         return major;
192 }
193
194 /*
195  * this interface is much simplified, currently we only need endtime.
196  */
197 __u32 lgss_inquire_context(struct gss_ctx *context_handle,
198                            unsigned long  *endtime)
199 {
200         LASSERT(context_handle);
201         LASSERT(context_handle->mech_type);
202         LASSERT(context_handle->mech_type->gm_ops);
203         LASSERT(context_handle->mech_type->gm_ops->gss_inquire_context);
204
205         return context_handle->mech_type->gm_ops
206                 ->gss_inquire_context(context_handle,
207                                       endtime);
208 }
209
210 /* gss_get_mic: compute a mic over message and return mic_token. */
211 __u32 lgss_get_mic(struct gss_ctx *context_handle,
212                    int msgcnt,
213                    rawobj_t *msg,
214                    int iovcnt,
215                    lnet_kiov_t *iovs,
216                    rawobj_t *mic_token)
217 {
218         LASSERT(context_handle);
219         LASSERT(context_handle->mech_type);
220         LASSERT(context_handle->mech_type->gm_ops);
221         LASSERT(context_handle->mech_type->gm_ops->gss_get_mic);
222
223         return context_handle->mech_type->gm_ops
224                 ->gss_get_mic(context_handle,
225                               msgcnt,
226                               msg,
227                               iovcnt,
228                               iovs,
229                               mic_token);
230 }
231
232 /* gss_verify_mic: check whether the provided mic_token verifies message. */
233 __u32 lgss_verify_mic(struct gss_ctx *context_handle,
234                       int msgcnt,
235                       rawobj_t *msg,
236                       int iovcnt,
237                       lnet_kiov_t *iovs,
238                       rawobj_t *mic_token)
239 {
240         LASSERT(context_handle);
241         LASSERT(context_handle->mech_type);
242         LASSERT(context_handle->mech_type->gm_ops);
243         LASSERT(context_handle->mech_type->gm_ops->gss_verify_mic);
244
245         return context_handle->mech_type->gm_ops
246                 ->gss_verify_mic(context_handle,
247                                  msgcnt,
248                                  msg,
249                                  iovcnt,
250                                  iovs,
251                                  mic_token);
252 }
253
254 __u32 lgss_wrap(struct gss_ctx *context_handle,
255                 rawobj_t *gsshdr,
256                 rawobj_t *msg,
257                 int msg_buflen,
258                 rawobj_t *out_token)
259 {
260         LASSERT(context_handle);
261         LASSERT(context_handle->mech_type);
262         LASSERT(context_handle->mech_type->gm_ops);
263         LASSERT(context_handle->mech_type->gm_ops->gss_wrap);
264
265         return context_handle->mech_type->gm_ops
266                 ->gss_wrap(context_handle, gsshdr, msg, msg_buflen, out_token);
267 }
268
269 __u32 lgss_unwrap(struct gss_ctx *context_handle,
270                   rawobj_t *gsshdr,
271                   rawobj_t *token,
272                   rawobj_t *out_msg)
273 {
274         LASSERT(context_handle);
275         LASSERT(context_handle->mech_type);
276         LASSERT(context_handle->mech_type->gm_ops);
277         LASSERT(context_handle->mech_type->gm_ops->gss_unwrap);
278
279         return context_handle->mech_type->gm_ops
280                 ->gss_unwrap(context_handle, gsshdr, token, out_msg);
281 }
282
283
284 __u32 lgss_prep_bulk(struct gss_ctx *context_handle,
285                      struct ptlrpc_bulk_desc *desc)
286 {
287         LASSERT(context_handle);
288         LASSERT(context_handle->mech_type);
289         LASSERT(context_handle->mech_type->gm_ops);
290         LASSERT(context_handle->mech_type->gm_ops->gss_prep_bulk);
291
292         return context_handle->mech_type->gm_ops
293                 ->gss_prep_bulk(context_handle, desc);
294 }
295
296 __u32 lgss_wrap_bulk(struct gss_ctx *context_handle,
297                      struct ptlrpc_bulk_desc *desc,
298                      rawobj_t *token,
299                      int adj_nob)
300 {
301         LASSERT(context_handle);
302         LASSERT(context_handle->mech_type);
303         LASSERT(context_handle->mech_type->gm_ops);
304         LASSERT(context_handle->mech_type->gm_ops->gss_wrap_bulk);
305
306         return context_handle->mech_type->gm_ops
307                 ->gss_wrap_bulk(context_handle, desc, token, adj_nob);
308 }
309
310 __u32 lgss_unwrap_bulk(struct gss_ctx *context_handle,
311                        struct ptlrpc_bulk_desc *desc,
312                        rawobj_t *token,
313                        int adj_nob)
314 {
315         LASSERT(context_handle);
316         LASSERT(context_handle->mech_type);
317         LASSERT(context_handle->mech_type->gm_ops);
318         LASSERT(context_handle->mech_type->gm_ops->gss_unwrap_bulk);
319
320         return context_handle->mech_type->gm_ops
321                 ->gss_unwrap_bulk(context_handle, desc, token, adj_nob);
322 }
323
324 /* gss_delete_sec_context: free all resources associated with context_handle.
325  * Note this differs from the RFC 2744-specified prototype in that we don't
326  * bother returning an output token, since it would never be used anyway. */
327
328 __u32 lgss_delete_sec_context(struct gss_ctx **context_handle)
329 {
330         struct gss_api_mech *mech;
331
332         CDEBUG(D_SEC, "deleting %p\n", *context_handle);
333
334         if (!*context_handle)
335                 return(GSS_S_NO_CONTEXT);
336
337         mech = (*context_handle)->mech_type;
338         if ((*context_handle)->internal_ctx_id != 0) {
339                 LASSERT(mech);
340                 LASSERT(mech->gm_ops);
341                 LASSERT(mech->gm_ops->gss_delete_sec_context);
342                 mech->gm_ops->gss_delete_sec_context(
343                                         (*context_handle)->internal_ctx_id);
344         }
345         if (mech)
346                 lgss_mech_put(mech);
347
348         OBD_FREE_PTR(*context_handle);
349         *context_handle=NULL;
350         return GSS_S_COMPLETE;
351 }
352
353 int lgss_display(struct gss_ctx *ctx,
354                  char           *buf,
355                  int             bufsize)
356 {
357         LASSERT(ctx);
358         LASSERT(ctx->mech_type);
359         LASSERT(ctx->mech_type->gm_ops);
360         LASSERT(ctx->mech_type->gm_ops->gss_display);
361
362         return ctx->mech_type->gm_ops->gss_display(ctx, buf, bufsize);
363 }