Whamcloud - gitweb
8dcca46be20cbe893c1ec40d70197a464292939c
[fs/lustre-release.git] / lustre / sec / gss / gss_krb5_mech.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_krb5_mech.c
12  *
13  *  Copyright (c) 2001 The Regents of the University of Michigan.
14  *  All rights reserved.
15  *
16  *  Andy Adamson <andros@umich.edu>
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 #ifndef EXPORT_SYMTAB
47 # define EXPORT_SYMTAB
48 #endif
49 #define DEBUG_SUBSYSTEM S_SEC
50 #ifdef __KERNEL__
51 #include <linux/init.h>
52 #include <linux/module.h>
53 #include <linux/slab.h>
54 #include <linux/crypto.h>
55 #else
56 #include <liblustre.h>
57 //#include "../kcrypto/libcrypto.h"
58 #endif
59
60 #include <libcfs/kp30.h>
61 #include <linux/obd.h>
62 #include <linux/obd_class.h>
63 #include <linux/obd_support.h>
64 #include <linux/lustre_idl.h>
65 #include <linux/lustre_net.h>
66 #include <linux/lustre_import.h>
67 #include <linux/lustre_sec.h>
68
69 #include "gss_err.h"
70 #include "gss_internal.h"
71 #include "gss_api.h"
72 #include "gss_krb5.h"
73
74 rawobj_t gss_mech_krb5_oid =
75    {9, "\052\206\110\206\367\022\001\002\002"};
76
77 static inline int
78 get_bytes(char **ptr, const char *end, void *res, int len)
79 {
80         char *p, *q;
81         p = *ptr;
82         q = p + len;
83         if (q > end || q < p)
84                 return -1;
85         memcpy(res, p, len);
86         *ptr = q;
87         return 0;
88 }
89
90 static inline int
91 get_rawobj(char **ptr, const char *end, rawobj_t *res)
92 {
93         char *p, *q;
94         p = *ptr;
95         if (get_bytes(&p, end, &res->len, sizeof(res->len)))
96                 return -1;
97         q = p + res->len;
98         if (q > end || q < p)
99                 return -1;
100         OBD_ALLOC(res->data, res->len);
101         if (!res->data)
102                 return -1;
103         memcpy(res->data, p, res->len);
104         *ptr = q;
105         return 0;
106 }
107
108 static inline int
109 get_key(char **p, char *end, struct crypto_tfm **res)
110 {
111         rawobj_t                key;
112         int                     alg, alg_mode;
113         char                   *alg_name;
114
115         if (get_bytes(p, end, &alg, sizeof(alg)))
116                 goto out_err;
117         if ((get_rawobj(p, end, &key)))
118                 goto out_err;
119
120         switch (alg) {
121                 case ENCTYPE_DES_CBC_RAW:
122                         alg_name = "des";
123                         alg_mode = CRYPTO_TFM_MODE_CBC;
124                         break;
125                 default:
126                         CERROR("unsupported algorithm %d\n", alg);
127                         goto out_err_free_key;
128         }
129         if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
130                 goto out_err_free_key;
131         if (crypto_cipher_setkey(*res, key.data, key.len))
132                 goto out_err_free_tfm;
133
134         OBD_FREE(key.data, key.len);
135         return 0;
136
137 out_err_free_tfm:
138         crypto_free_tfm(*res);
139 out_err_free_key:
140         OBD_FREE(key.data, key.len);
141 out_err:
142         return -1;
143 }
144
145 static __u32
146 gss_import_sec_context_kerberos(rawobj_t *inbuf,
147                                 struct gss_ctx *ctx_id)
148 {
149         char            *p = inbuf->data;
150         char            *end = inbuf->data + inbuf->len;
151         struct krb5_ctx *ctx;
152
153         OBD_ALLOC(ctx, sizeof(*ctx));
154         if (!ctx)
155                 goto out_err;
156
157         if (get_bytes(&p, end, &ctx->initiate, sizeof(ctx->initiate)))
158                 goto out_err_free_ctx;
159         if (get_bytes(&p, end, &ctx->seed_init, sizeof(ctx->seed_init)))
160                 goto out_err_free_ctx;
161         if (get_bytes(&p, end, ctx->seed, sizeof(ctx->seed)))
162                 goto out_err_free_ctx;
163         if (get_bytes(&p, end, &ctx->signalg, sizeof(ctx->signalg)))
164                 goto out_err_free_ctx;
165         if (get_bytes(&p, end, &ctx->sealalg, sizeof(ctx->sealalg)))
166                 goto out_err_free_ctx;
167         if (get_bytes(&p, end, &ctx->endtime, sizeof(ctx->endtime)))
168                 goto out_err_free_ctx;
169         if (get_bytes(&p, end, &ctx->seq_send, sizeof(ctx->seq_send)))
170                 goto out_err_free_ctx;
171         if (get_rawobj(&p, end, &ctx->mech_used))
172                 goto out_err_free_ctx;
173         if (get_key(&p, end, &ctx->enc))
174                 goto out_err_free_mech;
175         if (get_key(&p, end, &ctx->seq))
176                 goto out_err_free_key1;
177         if (p != end)
178                 goto out_err_free_key2;
179
180         ctx_id->internal_ctx_id = ctx;
181         CDEBUG(D_SEC, "Succesfully imported new context.\n");
182         return 0;
183
184 out_err_free_key2:
185         crypto_free_tfm(ctx->seq);
186 out_err_free_key1:
187         crypto_free_tfm(ctx->enc);
188 out_err_free_mech:
189         OBD_FREE(ctx->mech_used.data, ctx->mech_used.len);
190 out_err_free_ctx:
191         OBD_FREE(ctx, sizeof(*ctx));
192 out_err:
193         return GSS_S_FAILURE;
194 }
195
196 static __u32
197 gss_inquire_context_kerberos(struct gss_ctx    *context_handle,
198                              __u64             *endtime)
199 {
200         struct krb5_ctx *kctx = context_handle->internal_ctx_id;
201
202         *endtime = (__u64) kctx->endtime;
203         return GSS_S_COMPLETE;
204 }
205
206 static void
207 gss_delete_sec_context_kerberos(void *internal_ctx)
208 {
209         struct krb5_ctx *ctx = internal_ctx;
210
211         if (ctx->seq)
212                 crypto_free_tfm(ctx->seq);
213         if (ctx->enc)
214                 crypto_free_tfm(ctx->enc);
215         if (ctx->mech_used.data)
216                 OBD_FREE(ctx->mech_used.data, ctx->mech_used.len);
217         OBD_FREE(ctx, sizeof(*ctx));
218 }
219
220 /* XXX the following wrappers have become pointless; kill them. */
221 static __u32
222 gss_verify_mic_kerberos(struct gss_ctx *ctx,
223                         rawobj_t       *message,
224                         rawobj_t       *mic_token,
225                         __u32          *qstate)
226 {
227         struct krb5_ctx *kctx = ctx->internal_ctx_id;
228         __u32 maj_stat;
229         int qop_state;
230
231         maj_stat = krb5_read_token(kctx, mic_token, message, &qop_state);
232         if (!maj_stat && qop_state)
233             *qstate = qop_state;
234
235         CDEBUG(D_SEC, "returning %d\n", maj_stat);
236         return maj_stat;
237 }
238
239 static __u32
240 gss_get_mic_kerberos(struct gss_ctx    *ctx,
241                      __u32              qop,
242                      rawobj_t          *message,
243                      rawobj_t          *mic_token)
244 {
245         struct krb5_ctx *kctx = ctx->internal_ctx_id;
246         __u32 err;
247
248         err = krb5_make_token(kctx, qop, message, mic_token);
249
250         CDEBUG(D_SEC, "returning %d\n",err);
251         return err;
252 }
253
254 static struct gss_api_ops gss_kerberos_ops = {
255         .gss_import_sec_context     = gss_import_sec_context_kerberos,
256         .gss_inquire_context        = gss_inquire_context_kerberos,
257         .gss_get_mic                = gss_get_mic_kerberos,
258         .gss_verify_mic             = gss_verify_mic_kerberos,
259         .gss_wrap                   = gss_wrap_kerberos,
260         .gss_unwrap                 = gss_unwrap_kerberos,
261         .gss_delete_sec_context     = gss_delete_sec_context_kerberos,
262 };
263
264 static struct subflavor_desc gss_kerberos_sfs[] = {
265         {
266                 .subflavor      = PTLRPC_SEC_GSS_KRB5,
267                 .qop            = 0,
268                 .service        = PTLRPC_SEC_TYPE_NONE,
269                 .name           = "krb5"
270         },
271         {
272                 .subflavor      = PTLRPC_SEC_GSS_KRB5I,
273                 .qop            = 0,
274                 .service        = PTLRPC_SEC_TYPE_AUTH,
275                 .name           = "krb5i"
276         },
277         {
278                 .subflavor      = PTLRPC_SEC_GSS_KRB5P,
279                 .qop            = 0,
280                 .service        = PTLRPC_SEC_TYPE_PRIV,
281                 .name           = "krb5p"
282         }
283 };
284
285 static struct gss_api_mech gss_kerberos_mech = {
286         .gm_name        = "krb5",
287         .gm_owner       = THIS_MODULE,
288         .gm_ops         = &gss_kerberos_ops,
289         .gm_sf_num      = 3,
290         .gm_sfs         = gss_kerberos_sfs,
291 };
292
293 /*static*/ int __init init_kerberos_module(void)
294 {
295         int status;
296
297         status = kgss_mech_register(&gss_kerberos_mech);
298         if (status)
299                 CERROR("Failed to register kerberos gss mechanism!\n");
300         return status;
301 }
302
303 /*static*/ void __exit cleanup_kerberos_module(void)
304 {
305         kgss_mech_unregister(&gss_kerberos_mech);
306 }
307
308 /* XXX enable this when module works */
309 #if 0
310 MODULE_LICENSE("GPL");
311 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
312 MODULE_DESCRIPTION("GSS Krb5 mechanism for Lustre");
313
314 module_init(init_kerberos_module);
315 module_exit(cleanup_kerberos_module);
316 #endif