]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/net/sunrpc/gss_krb5_mech.c | |
3 | * | |
81d4a433 | 4 | * Copyright (c) 2001-2008 The Regents of the University of Michigan. |
1da177e4 LT |
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 | ||
378c6697 | 37 | #include <linux/err.h> |
1da177e4 LT |
38 | #include <linux/module.h> |
39 | #include <linux/init.h> | |
40 | #include <linux/types.h> | |
41 | #include <linux/slab.h> | |
42 | #include <linux/sunrpc/auth.h> | |
1da177e4 LT |
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 | ||
47d84807 KC |
51 | static struct gss_api_mech gss_kerberos_mech; /* forward declaration */ |
52 | ||
81d4a433 KC |
53 | static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { |
54 | /* | |
55 | * DES (All DES enctypes are mapped to the same gss functionality) | |
56 | */ | |
57 | { | |
58 | .etype = ENCTYPE_DES_CBC_RAW, | |
59 | .ctype = CKSUMTYPE_RSA_MD5, | |
60 | .name = "des-cbc-crc", | |
61 | .encrypt_name = "cbc(des)", | |
62 | .cksum_name = "md5", | |
63 | .encrypt = krb5_encrypt, | |
64 | .decrypt = krb5_decrypt, | |
4891f2d0 | 65 | .mk_key = NULL, |
81d4a433 KC |
66 | .signalg = SGN_ALG_DES_MAC_MD5, |
67 | .sealalg = SEAL_ALG_DES, | |
68 | .keybytes = 7, | |
69 | .keylength = 8, | |
70 | .blocksize = 8, | |
71 | .cksumlength = 8, | |
e1f6c07b | 72 | .keyed_cksum = 0, |
81d4a433 KC |
73 | }, |
74 | }; | |
75 | ||
76 | static const int num_supported_enctypes = | |
77 | ARRAY_SIZE(supported_gss_krb5_enctypes); | |
78 | ||
79 | static int | |
80 | supported_gss_krb5_enctype(int etype) | |
81 | { | |
82 | int i; | |
83 | for (i = 0; i < num_supported_enctypes; i++) | |
84 | if (supported_gss_krb5_enctypes[i].etype == etype) | |
85 | return 1; | |
86 | return 0; | |
87 | } | |
88 | ||
89 | static const struct gss_krb5_enctype * | |
90 | get_gss_krb5_enctype(int etype) | |
91 | { | |
92 | int i; | |
93 | for (i = 0; i < num_supported_enctypes; i++) | |
94 | if (supported_gss_krb5_enctypes[i].etype == etype) | |
95 | return &supported_gss_krb5_enctypes[i]; | |
96 | return NULL; | |
97 | } | |
98 | ||
1da177e4 LT |
99 | static const void * |
100 | simple_get_bytes(const void *p, const void *end, void *res, int len) | |
101 | { | |
102 | const void *q = (const void *)((const char *)p + len); | |
103 | if (unlikely(q > end || q < p)) | |
104 | return ERR_PTR(-EFAULT); | |
105 | memcpy(res, p, len); | |
106 | return q; | |
107 | } | |
108 | ||
109 | static const void * | |
110 | simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) | |
111 | { | |
112 | const void *q; | |
113 | unsigned int len; | |
114 | ||
115 | p = simple_get_bytes(p, end, &len, sizeof(len)); | |
116 | if (IS_ERR(p)) | |
117 | return p; | |
118 | q = (const void *)((const char *)p + len); | |
119 | if (unlikely(q > end || q < p)) | |
120 | return ERR_PTR(-EFAULT); | |
0f38b873 | 121 | res->data = kmemdup(p, len, GFP_NOFS); |
1da177e4 LT |
122 | if (unlikely(res->data == NULL)) |
123 | return ERR_PTR(-ENOMEM); | |
1da177e4 LT |
124 | res->len = len; |
125 | return q; | |
126 | } | |
127 | ||
128 | static inline const void * | |
81d4a433 KC |
129 | get_key(const void *p, const void *end, |
130 | struct krb5_ctx *ctx, struct crypto_blkcipher **res) | |
1da177e4 LT |
131 | { |
132 | struct xdr_netobj key; | |
378c6697 | 133 | int alg; |
1da177e4 LT |
134 | |
135 | p = simple_get_bytes(p, end, &alg, sizeof(alg)); | |
136 | if (IS_ERR(p)) | |
137 | goto out_err; | |
81d4a433 KC |
138 | |
139 | switch (alg) { | |
140 | case ENCTYPE_DES_CBC_CRC: | |
141 | case ENCTYPE_DES_CBC_MD4: | |
142 | case ENCTYPE_DES_CBC_MD5: | |
143 | /* Map all these key types to ENCTYPE_DES_CBC_RAW */ | |
144 | alg = ENCTYPE_DES_CBC_RAW; | |
145 | break; | |
146 | } | |
147 | ||
148 | if (!supported_gss_krb5_enctype(alg)) { | |
149 | printk(KERN_WARNING "gss_kerberos_mech: unsupported " | |
150 | "encryption key algorithm %d\n", alg); | |
151 | goto out_err; | |
152 | } | |
1da177e4 LT |
153 | p = simple_get_netobj(p, end, &key); |
154 | if (IS_ERR(p)) | |
155 | goto out_err; | |
156 | ||
81d4a433 KC |
157 | *res = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0, |
158 | CRYPTO_ALG_ASYNC); | |
378c6697 | 159 | if (IS_ERR(*res)) { |
81d4a433 KC |
160 | printk(KERN_WARNING "gss_kerberos_mech: unable to initialize " |
161 | "crypto algorithm %s\n", ctx->gk5e->encrypt_name); | |
378c6697 | 162 | *res = NULL; |
1da177e4 | 163 | goto out_err_free_key; |
9e56904e | 164 | } |
378c6697 | 165 | if (crypto_blkcipher_setkey(*res, key.data, key.len)) { |
81d4a433 KC |
166 | printk(KERN_WARNING "gss_kerberos_mech: error setting key for " |
167 | "crypto algorithm %s\n", ctx->gk5e->encrypt_name); | |
1da177e4 | 168 | goto out_err_free_tfm; |
9e56904e | 169 | } |
1da177e4 LT |
170 | |
171 | kfree(key.data); | |
172 | return p; | |
173 | ||
174 | out_err_free_tfm: | |
378c6697 | 175 | crypto_free_blkcipher(*res); |
1da177e4 LT |
176 | out_err_free_key: |
177 | kfree(key.data); | |
178 | p = ERR_PTR(-EINVAL); | |
179 | out_err: | |
180 | return p; | |
181 | } | |
182 | ||
183 | static int | |
a8cc1cb7 | 184 | gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx) |
1da177e4 | 185 | { |
e678e06b | 186 | int tmp; |
1da177e4 | 187 | |
1da177e4 LT |
188 | p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); |
189 | if (IS_ERR(p)) | |
a8cc1cb7 KC |
190 | goto out_err; |
191 | ||
192 | /* Old format supports only DES! Any other enctype uses new format */ | |
1ac3719a | 193 | ctx->enctype = ENCTYPE_DES_CBC_RAW; |
a8cc1cb7 | 194 | |
81d4a433 KC |
195 | ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); |
196 | if (ctx->gk5e == NULL) | |
197 | goto out_err; | |
198 | ||
717757ad BF |
199 | /* The downcall format was designed before we completely understood |
200 | * the uses of the context fields; so it includes some stuff we | |
201 | * just give some minimal sanity-checking, and some we ignore | |
202 | * completely (like the next twenty bytes): */ | |
203 | if (unlikely(p + 20 > end || p + 20 < p)) | |
a8cc1cb7 | 204 | goto out_err; |
717757ad | 205 | p += 20; |
e678e06b | 206 | p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); |
1da177e4 | 207 | if (IS_ERR(p)) |
a8cc1cb7 | 208 | goto out_err; |
ef338bee KC |
209 | if (tmp != SGN_ALG_DES_MAC_MD5) { |
210 | p = ERR_PTR(-ENOSYS); | |
a8cc1cb7 | 211 | goto out_err; |
ef338bee | 212 | } |
d922a84a | 213 | p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); |
1da177e4 | 214 | if (IS_ERR(p)) |
a8cc1cb7 | 215 | goto out_err; |
ef338bee KC |
216 | if (tmp != SEAL_ALG_DES) { |
217 | p = ERR_PTR(-ENOSYS); | |
a8cc1cb7 | 218 | goto out_err; |
ef338bee | 219 | } |
1da177e4 LT |
220 | p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); |
221 | if (IS_ERR(p)) | |
a8cc1cb7 | 222 | goto out_err; |
1da177e4 LT |
223 | p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send)); |
224 | if (IS_ERR(p)) | |
a8cc1cb7 | 225 | goto out_err; |
1da177e4 LT |
226 | p = simple_get_netobj(p, end, &ctx->mech_used); |
227 | if (IS_ERR(p)) | |
a8cc1cb7 | 228 | goto out_err; |
81d4a433 | 229 | p = get_key(p, end, ctx, &ctx->enc); |
1da177e4 LT |
230 | if (IS_ERR(p)) |
231 | goto out_err_free_mech; | |
81d4a433 | 232 | p = get_key(p, end, ctx, &ctx->seq); |
1da177e4 LT |
233 | if (IS_ERR(p)) |
234 | goto out_err_free_key1; | |
235 | if (p != end) { | |
236 | p = ERR_PTR(-EFAULT); | |
237 | goto out_err_free_key2; | |
238 | } | |
239 | ||
1da177e4 LT |
240 | return 0; |
241 | ||
242 | out_err_free_key2: | |
378c6697 | 243 | crypto_free_blkcipher(ctx->seq); |
1da177e4 | 244 | out_err_free_key1: |
378c6697 | 245 | crypto_free_blkcipher(ctx->enc); |
1da177e4 LT |
246 | out_err_free_mech: |
247 | kfree(ctx->mech_used.data); | |
1da177e4 LT |
248 | out_err: |
249 | return PTR_ERR(p); | |
250 | } | |
251 | ||
47d84807 KC |
252 | struct crypto_blkcipher * |
253 | context_v2_alloc_cipher(struct krb5_ctx *ctx, u8 *key) | |
254 | { | |
255 | struct crypto_blkcipher *cp; | |
256 | ||
257 | cp = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, | |
258 | 0, CRYPTO_ALG_ASYNC); | |
259 | if (IS_ERR(cp)) { | |
260 | dprintk("gss_kerberos_mech: unable to initialize " | |
261 | "crypto algorithm %s\n", ctx->gk5e->encrypt_name); | |
262 | return NULL; | |
263 | } | |
264 | if (crypto_blkcipher_setkey(cp, key, ctx->gk5e->keylength)) { | |
265 | dprintk("gss_kerberos_mech: error setting key for " | |
266 | "crypto algorithm %s\n", ctx->gk5e->encrypt_name); | |
267 | crypto_free_blkcipher(cp); | |
268 | return NULL; | |
269 | } | |
270 | return cp; | |
271 | } | |
272 | ||
273 | static inline void | |
274 | set_cdata(u8 cdata[GSS_KRB5_K5CLENGTH], u32 usage, u8 seed) | |
275 | { | |
276 | cdata[0] = (usage>>24)&0xff; | |
277 | cdata[1] = (usage>>16)&0xff; | |
278 | cdata[2] = (usage>>8)&0xff; | |
279 | cdata[3] = usage&0xff; | |
280 | cdata[4] = seed; | |
281 | } | |
282 | ||
283 | static int | |
284 | context_derive_keys_des3(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen) | |
285 | { | |
286 | struct xdr_netobj c, keyin, keyout; | |
287 | u8 cdata[GSS_KRB5_K5CLENGTH]; | |
288 | u32 err; | |
289 | ||
290 | c.len = GSS_KRB5_K5CLENGTH; | |
291 | c.data = cdata; | |
292 | ||
293 | keyin.data = rawkey; | |
294 | keyin.len = keylen; | |
295 | keyout.len = keylen; | |
296 | ||
297 | /* seq uses the raw key */ | |
298 | ctx->seq = context_v2_alloc_cipher(ctx, rawkey); | |
299 | if (ctx->seq == NULL) | |
300 | goto out_err; | |
301 | ||
302 | ctx->enc = context_v2_alloc_cipher(ctx, rawkey); | |
303 | if (ctx->enc == NULL) | |
304 | goto out_free_seq; | |
305 | ||
306 | /* derive cksum */ | |
307 | set_cdata(cdata, KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM); | |
308 | keyout.data = ctx->cksum; | |
309 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c); | |
310 | if (err) { | |
311 | dprintk("%s: Error %d deriving cksum key\n", | |
312 | __func__, err); | |
313 | goto out_free_enc; | |
314 | } | |
315 | ||
316 | return 0; | |
317 | ||
318 | out_free_enc: | |
319 | crypto_free_blkcipher(ctx->enc); | |
320 | out_free_seq: | |
321 | crypto_free_blkcipher(ctx->seq); | |
322 | out_err: | |
323 | return -EINVAL; | |
324 | } | |
325 | ||
326 | static int | |
327 | context_derive_keys_new(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen) | |
328 | { | |
329 | struct xdr_netobj c, keyin, keyout; | |
330 | u8 cdata[GSS_KRB5_K5CLENGTH]; | |
331 | u32 err; | |
332 | ||
333 | c.len = GSS_KRB5_K5CLENGTH; | |
334 | c.data = cdata; | |
335 | ||
336 | keyin.data = rawkey; | |
337 | keyin.len = keylen; | |
338 | keyout.len = keylen; | |
339 | ||
340 | /* initiator seal encryption */ | |
341 | set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); | |
342 | keyout.data = ctx->initiator_seal; | |
343 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c); | |
344 | if (err) { | |
345 | dprintk("%s: Error %d deriving initiator_seal key\n", | |
346 | __func__, err); | |
347 | goto out_err; | |
348 | } | |
349 | ctx->initiator_enc = context_v2_alloc_cipher(ctx, ctx->initiator_seal); | |
350 | if (ctx->initiator_enc == NULL) | |
351 | goto out_err; | |
352 | ||
353 | /* acceptor seal encryption */ | |
354 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); | |
355 | keyout.data = ctx->acceptor_seal; | |
356 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c); | |
357 | if (err) { | |
358 | dprintk("%s: Error %d deriving acceptor_seal key\n", | |
359 | __func__, err); | |
360 | goto out_free_initiator_enc; | |
361 | } | |
362 | ctx->acceptor_enc = context_v2_alloc_cipher(ctx, ctx->acceptor_seal); | |
363 | if (ctx->acceptor_enc == NULL) | |
364 | goto out_free_initiator_enc; | |
365 | ||
366 | /* initiator sign checksum */ | |
367 | set_cdata(cdata, KG_USAGE_INITIATOR_SIGN, KEY_USAGE_SEED_CHECKSUM); | |
368 | keyout.data = ctx->initiator_sign; | |
369 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c); | |
370 | if (err) { | |
371 | dprintk("%s: Error %d deriving initiator_sign key\n", | |
372 | __func__, err); | |
373 | goto out_free_acceptor_enc; | |
374 | } | |
375 | ||
376 | /* acceptor sign checksum */ | |
377 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SIGN, KEY_USAGE_SEED_CHECKSUM); | |
378 | keyout.data = ctx->acceptor_sign; | |
379 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c); | |
380 | if (err) { | |
381 | dprintk("%s: Error %d deriving acceptor_sign key\n", | |
382 | __func__, err); | |
383 | goto out_free_acceptor_enc; | |
384 | } | |
385 | ||
386 | /* initiator seal integrity */ | |
387 | set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_INTEGRITY); | |
388 | keyout.data = ctx->initiator_integ; | |
389 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c); | |
390 | if (err) { | |
391 | dprintk("%s: Error %d deriving initiator_integ key\n", | |
392 | __func__, err); | |
393 | goto out_free_acceptor_enc; | |
394 | } | |
395 | ||
396 | /* acceptor seal integrity */ | |
397 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_INTEGRITY); | |
398 | keyout.data = ctx->acceptor_integ; | |
399 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c); | |
400 | if (err) { | |
401 | dprintk("%s: Error %d deriving acceptor_integ key\n", | |
402 | __func__, err); | |
403 | goto out_free_acceptor_enc; | |
404 | } | |
405 | ||
406 | return 0; | |
407 | ||
408 | out_free_acceptor_enc: | |
409 | crypto_free_blkcipher(ctx->acceptor_enc); | |
410 | out_free_initiator_enc: | |
411 | crypto_free_blkcipher(ctx->initiator_enc); | |
412 | out_err: | |
413 | return -EINVAL; | |
414 | } | |
415 | ||
416 | static int | |
417 | gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx) | |
418 | { | |
419 | u8 rawkey[GSS_KRB5_MAX_KEYLEN]; | |
420 | int keylen; | |
421 | ||
422 | p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags)); | |
423 | if (IS_ERR(p)) | |
424 | goto out_err; | |
425 | ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR; | |
426 | ||
427 | p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); | |
428 | if (IS_ERR(p)) | |
429 | goto out_err; | |
430 | p = simple_get_bytes(p, end, &ctx->seq_send64, sizeof(ctx->seq_send64)); | |
431 | if (IS_ERR(p)) | |
432 | goto out_err; | |
433 | /* set seq_send for use by "older" enctypes */ | |
434 | ctx->seq_send = ctx->seq_send64; | |
435 | if (ctx->seq_send64 != ctx->seq_send) { | |
436 | dprintk("%s: seq_send64 %lx, seq_send %x overflow?\n", __func__, | |
437 | (long unsigned)ctx->seq_send64, ctx->seq_send); | |
438 | goto out_err; | |
439 | } | |
440 | p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype)); | |
441 | if (IS_ERR(p)) | |
442 | goto out_err; | |
443 | ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); | |
444 | if (ctx->gk5e == NULL) { | |
445 | dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n", | |
446 | ctx->enctype); | |
447 | p = ERR_PTR(-EINVAL); | |
448 | goto out_err; | |
449 | } | |
450 | keylen = ctx->gk5e->keylength; | |
451 | ||
452 | p = simple_get_bytes(p, end, rawkey, keylen); | |
453 | if (IS_ERR(p)) | |
454 | goto out_err; | |
455 | ||
456 | if (p != end) { | |
457 | p = ERR_PTR(-EINVAL); | |
458 | goto out_err; | |
459 | } | |
460 | ||
461 | ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data, | |
462 | gss_kerberos_mech.gm_oid.len, GFP_KERNEL); | |
463 | if (unlikely(ctx->mech_used.data == NULL)) { | |
464 | p = ERR_PTR(-ENOMEM); | |
465 | goto out_err; | |
466 | } | |
467 | ctx->mech_used.len = gss_kerberos_mech.gm_oid.len; | |
468 | ||
469 | switch (ctx->enctype) { | |
470 | case ENCTYPE_DES3_CBC_RAW: | |
471 | return context_derive_keys_des3(ctx, rawkey, keylen); | |
472 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | |
473 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | |
474 | return context_derive_keys_new(ctx, rawkey, keylen); | |
475 | default: | |
476 | return -EINVAL; | |
477 | } | |
478 | ||
479 | out_err: | |
480 | return PTR_ERR(p); | |
481 | } | |
482 | ||
a8cc1cb7 KC |
483 | static int |
484 | gss_import_sec_context_kerberos(const void *p, size_t len, | |
485 | struct gss_ctx *ctx_id) | |
486 | { | |
487 | const void *end = (const void *)((const char *)p + len); | |
488 | struct krb5_ctx *ctx; | |
489 | int ret; | |
490 | ||
491 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | |
492 | if (ctx == NULL) | |
493 | return -ENOMEM; | |
494 | ||
495 | if (len == 85) | |
496 | ret = gss_import_v1_context(p, end, ctx); | |
497 | else | |
47d84807 | 498 | ret = gss_import_v2_context(p, end, ctx); |
a8cc1cb7 KC |
499 | |
500 | if (ret == 0) | |
501 | ctx_id->internal_ctx_id = ctx; | |
502 | else | |
503 | kfree(ctx); | |
504 | ||
505 | dprintk("RPC: %s: returning %d\n", __func__, ret); | |
506 | return ret; | |
507 | } | |
508 | ||
1da177e4 LT |
509 | static void |
510 | gss_delete_sec_context_kerberos(void *internal_ctx) { | |
511 | struct krb5_ctx *kctx = internal_ctx; | |
512 | ||
378c6697 HX |
513 | crypto_free_blkcipher(kctx->seq); |
514 | crypto_free_blkcipher(kctx->enc); | |
47d84807 KC |
515 | crypto_free_blkcipher(kctx->acceptor_enc); |
516 | crypto_free_blkcipher(kctx->initiator_enc); | |
573dbd95 | 517 | kfree(kctx->mech_used.data); |
1da177e4 LT |
518 | kfree(kctx); |
519 | } | |
520 | ||
f1c0a861 | 521 | static const struct gss_api_ops gss_kerberos_ops = { |
1da177e4 LT |
522 | .gss_import_sec_context = gss_import_sec_context_kerberos, |
523 | .gss_get_mic = gss_get_mic_kerberos, | |
524 | .gss_verify_mic = gss_verify_mic_kerberos, | |
14ae162c BF |
525 | .gss_wrap = gss_wrap_kerberos, |
526 | .gss_unwrap = gss_unwrap_kerberos, | |
1da177e4 LT |
527 | .gss_delete_sec_context = gss_delete_sec_context_kerberos, |
528 | }; | |
529 | ||
530 | static struct pf_desc gss_kerberos_pfs[] = { | |
531 | [0] = { | |
532 | .pseudoflavor = RPC_AUTH_GSS_KRB5, | |
533 | .service = RPC_GSS_SVC_NONE, | |
534 | .name = "krb5", | |
535 | }, | |
536 | [1] = { | |
537 | .pseudoflavor = RPC_AUTH_GSS_KRB5I, | |
538 | .service = RPC_GSS_SVC_INTEGRITY, | |
539 | .name = "krb5i", | |
540 | }, | |
14ae162c BF |
541 | [2] = { |
542 | .pseudoflavor = RPC_AUTH_GSS_KRB5P, | |
543 | .service = RPC_GSS_SVC_PRIVACY, | |
544 | .name = "krb5p", | |
545 | }, | |
1da177e4 LT |
546 | }; |
547 | ||
548 | static struct gss_api_mech gss_kerberos_mech = { | |
549 | .gm_name = "krb5", | |
550 | .gm_owner = THIS_MODULE, | |
ae4c40b1 | 551 | .gm_oid = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}, |
1da177e4 LT |
552 | .gm_ops = &gss_kerberos_ops, |
553 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), | |
554 | .gm_pfs = gss_kerberos_pfs, | |
683ac665 | 555 | .gm_upcall_enctypes = "enctypes=3,1,2 ", |
1da177e4 LT |
556 | }; |
557 | ||
558 | static int __init init_kerberos_module(void) | |
559 | { | |
560 | int status; | |
561 | ||
562 | status = gss_mech_register(&gss_kerberos_mech); | |
563 | if (status) | |
564 | printk("Failed to register kerberos gss mechanism!\n"); | |
565 | return status; | |
566 | } | |
567 | ||
568 | static void __exit cleanup_kerberos_module(void) | |
569 | { | |
570 | gss_mech_unregister(&gss_kerberos_mech); | |
571 | } | |
572 | ||
573 | MODULE_LICENSE("GPL"); | |
574 | module_init(init_kerberos_module); | |
575 | module_exit(cleanup_kerberos_module); |