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