vserver 1.9.5.x5
[linux-2.6.git] / net / sunrpc / auth_gss / gss_krb5_mech.c
1 /*
2  *  linux/net/sunrpc/gss_krb5_mech.c
3  *
4  *  Copyright (c) 2001 The Regents of the University of Michigan.
5  *  All rights reserved.
6  *
7  *  Andy Adamson <andros@umich.edu>
8  *  J. Bruce Fields <bfields@umich.edu>
9  *
10  *  Redistribution and use in source and binary forms, with or without
11  *  modification, are permitted provided that the following conditions
12  *  are met:
13  *
14  *  1. Redistributions of source code must retain the above copyright
15  *     notice, this list of conditions and the following disclaimer.
16  *  2. Redistributions in binary form must reproduce the above copyright
17  *     notice, this list of conditions and the following disclaimer in the
18  *     documentation and/or other materials provided with the distribution.
19  *  3. Neither the name of the University nor the names of its
20  *     contributors may be used to endorse or promote products derived
21  *     from this software without specific prior written permission.
22  *
23  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  */
36
37 #include <linux/module.h>
38 #include <linux/init.h>
39 #include <linux/types.h>
40 #include <linux/slab.h>
41 #include <linux/sunrpc/auth.h>
42 #include <linux/in.h>
43 #include <linux/sunrpc/gss_krb5.h>
44 #include <linux/sunrpc/xdr.h>
45 #include <linux/crypto.h>
46
47 #ifdef RPC_DEBUG
48 # define RPCDBG_FACILITY        RPCDBG_AUTH
49 #endif
50
51 static inline int
52 get_bytes(char **ptr, const char *end, void *res, int len)
53 {
54         char *p, *q;
55         p = *ptr;
56         q = p + len;
57         if (q > end || q < p)
58                 return -1;
59         memcpy(res, p, len);
60         *ptr = q;
61         return 0;
62 }
63
64 static inline int
65 get_netobj(char **ptr, const char *end, struct xdr_netobj *res)
66 {
67         char *p, *q;
68         p = *ptr;
69         if (get_bytes(&p, end, &res->len, sizeof(res->len)))
70                 return -1;
71         q = p + res->len;
72         if (q > end || q < p)
73                 return -1;
74         if (!(res->data = kmalloc(res->len, GFP_KERNEL)))
75                 return -1;
76         memcpy(res->data, p, res->len);
77         *ptr = q;
78         return 0;
79 }
80
81 static inline int
82 get_key(char **p, char *end, struct crypto_tfm **res)
83 {
84         struct xdr_netobj       key;
85         int                     alg, alg_mode;
86         char                    *alg_name;
87
88         if (get_bytes(p, end, &alg, sizeof(alg)))
89                 goto out_err;
90         if ((get_netobj(p, end, &key)))
91                 goto out_err;
92
93         switch (alg) {
94                 case ENCTYPE_DES_CBC_RAW:
95                         alg_name = "des";
96                         alg_mode = CRYPTO_TFM_MODE_CBC;
97                         break;
98                 default:
99                         dprintk("RPC:      get_key: unsupported algorithm %d\n", alg);
100                         goto out_err_free_key;
101         }
102         if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
103                 goto out_err_free_key;
104         if (crypto_cipher_setkey(*res, key.data, key.len))
105                 goto out_err_free_tfm;
106
107         kfree(key.data);
108         return 0;
109
110 out_err_free_tfm:
111         crypto_free_tfm(*res);
112 out_err_free_key:
113         kfree(key.data);
114 out_err:
115         return -1;
116 }
117
118 static u32
119 gss_import_sec_context_kerberos(struct xdr_netobj *inbuf,
120                                 struct gss_ctx *ctx_id)
121 {
122         char    *p = inbuf->data;
123         char    *end = inbuf->data + inbuf->len;
124         struct  krb5_ctx *ctx;
125
126         if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
127                 goto out_err;
128         memset(ctx, 0, sizeof(*ctx));
129
130         if (get_bytes(&p, end, &ctx->initiate, sizeof(ctx->initiate)))
131                 goto out_err_free_ctx;
132         if (get_bytes(&p, end, &ctx->seed_init, sizeof(ctx->seed_init)))
133                 goto out_err_free_ctx;
134         if (get_bytes(&p, end, ctx->seed, sizeof(ctx->seed)))
135                 goto out_err_free_ctx;
136         if (get_bytes(&p, end, &ctx->signalg, sizeof(ctx->signalg)))
137                 goto out_err_free_ctx;
138         if (get_bytes(&p, end, &ctx->sealalg, sizeof(ctx->sealalg)))
139                 goto out_err_free_ctx;
140         if (get_bytes(&p, end, &ctx->endtime, sizeof(ctx->endtime)))
141                 goto out_err_free_ctx;
142         if (get_bytes(&p, end, &ctx->seq_send, sizeof(ctx->seq_send)))
143                 goto out_err_free_ctx;
144         if (get_netobj(&p, end, &ctx->mech_used))
145                 goto out_err_free_ctx;
146         if (get_key(&p, end, &ctx->enc))
147                 goto out_err_free_mech;
148         if (get_key(&p, end, &ctx->seq))
149                 goto out_err_free_key1;
150         if (p != end)
151                 goto out_err_free_key2;
152
153         ctx_id->internal_ctx_id = ctx;
154         dprintk("RPC:      Succesfully imported new context.\n");
155         return 0;
156
157 out_err_free_key2:
158         crypto_free_tfm(ctx->seq);
159 out_err_free_key1:
160         crypto_free_tfm(ctx->enc);
161 out_err_free_mech:
162         kfree(ctx->mech_used.data);
163 out_err_free_ctx:
164         kfree(ctx);
165 out_err:
166         return GSS_S_FAILURE;
167 }
168
169 static void
170 gss_delete_sec_context_kerberos(void *internal_ctx) {
171         struct krb5_ctx *kctx = internal_ctx;
172
173         if (kctx->seq)
174                 crypto_free_tfm(kctx->seq);
175         if (kctx->enc)
176                 crypto_free_tfm(kctx->enc);
177         if (kctx->mech_used.data)
178                 kfree(kctx->mech_used.data);
179         kfree(kctx);
180 }
181
182 static u32
183 gss_verify_mic_kerberos(struct gss_ctx          *ctx,
184                         struct xdr_buf          *message,
185                         struct xdr_netobj       *mic_token,
186                         u32                     *qstate) {
187         u32 maj_stat = 0;
188         int qop_state;
189         struct krb5_ctx *kctx = ctx->internal_ctx_id;
190
191         maj_stat = krb5_read_token(kctx, mic_token, message, &qop_state,
192                                    KG_TOK_MIC_MSG);
193         if (!maj_stat && qop_state)
194             *qstate = qop_state;
195
196         dprintk("RPC:      gss_verify_mic_kerberos returning %d\n", maj_stat);
197         return maj_stat;
198 }
199
200 static u32
201 gss_get_mic_kerberos(struct gss_ctx     *ctx,
202                      u32                qop,
203                      struct xdr_buf     *message,
204                      struct xdr_netobj  *mic_token) {
205         u32 err = 0;
206         struct krb5_ctx *kctx = ctx->internal_ctx_id;
207
208         err = krb5_make_token(kctx, qop, message, mic_token, KG_TOK_MIC_MSG);
209
210         dprintk("RPC:      gss_get_mic_kerberos returning %d\n",err);
211
212         return err;
213 }
214
215 static struct gss_api_ops gss_kerberos_ops = {
216         .gss_import_sec_context = gss_import_sec_context_kerberos,
217         .gss_get_mic            = gss_get_mic_kerberos,
218         .gss_verify_mic         = gss_verify_mic_kerberos,
219         .gss_delete_sec_context = gss_delete_sec_context_kerberos,
220 };
221
222 static struct pf_desc gss_kerberos_pfs[] = {
223         [0] = {
224                 .pseudoflavor = RPC_AUTH_GSS_KRB5,
225                 .service = RPC_GSS_SVC_NONE,
226                 .name = "krb5",
227         },
228         [1] = {
229                 .pseudoflavor = RPC_AUTH_GSS_KRB5I,
230                 .service = RPC_GSS_SVC_INTEGRITY,
231                 .name = "krb5i",
232         },
233 };
234
235 static struct gss_api_mech gss_kerberos_mech = {
236         .gm_name        = "krb5",
237         .gm_owner       = THIS_MODULE,
238         .gm_ops         = &gss_kerberos_ops,
239         .gm_pf_num      = ARRAY_SIZE(gss_kerberos_pfs),
240         .gm_pfs         = gss_kerberos_pfs,
241 };
242
243 static int __init init_kerberos_module(void)
244 {
245         int status;
246
247         status = gss_mech_register(&gss_kerberos_mech);
248         if (status)
249                 printk("Failed to register kerberos gss mechanism!\n");
250         return status;
251 }
252
253 static void __exit cleanup_kerberos_module(void)
254 {
255         gss_mech_unregister(&gss_kerberos_mech);
256 }
257
258 MODULE_LICENSE("GPL");
259 module_init(init_kerberos_module);
260 module_exit(cleanup_kerberos_module);