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