Whamcloud - gitweb
b=15266
[fs/lustre-release.git] / lustre / ptlrpc / 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  *
6  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
7  *
8  * Author: Eric Mei <ericm@clusterfs.com>
9  */
10
11 /*
12  *  linux/net/sunrpc/gss_krb5_mech.c
13  *  linux/net/sunrpc/gss_krb5_crypto.c
14  *  linux/net/sunrpc/gss_krb5_seal.c
15  *  linux/net/sunrpc/gss_krb5_seqnum.c
16  *  linux/net/sunrpc/gss_krb5_unseal.c
17  *
18  *  Copyright (c) 2001 The Regents of the University of Michigan.
19  *  All rights reserved.
20  *
21  *  Andy Adamson <andros@umich.edu>
22  *  J. Bruce Fields <bfields@umich.edu>
23  *
24  *  Redistribution and use in source and binary forms, with or without
25  *  modification, are permitted provided that the following conditions
26  *  are met:
27  *
28  *  1. Redistributions of source code must retain the above copyright
29  *     notice, this list of conditions and the following disclaimer.
30  *  2. Redistributions in binary form must reproduce the above copyright
31  *     notice, this list of conditions and the following disclaimer in the
32  *     documentation and/or other materials provided with the distribution.
33  *  3. Neither the name of the University nor the names of its
34  *     contributors may be used to endorse or promote products derived
35  *     from this software without specific prior written permission.
36  *
37  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
38  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
39  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
43  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
44  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
46  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  *
49  */
50
51 #ifndef EXPORT_SYMTAB
52 # define EXPORT_SYMTAB
53 #endif
54 #define DEBUG_SUBSYSTEM S_SEC
55 #ifdef __KERNEL__
56 #include <linux/init.h>
57 #include <linux/module.h>
58 #include <linux/slab.h>
59 #include <linux/crypto.h>
60 #include <linux/random.h>
61 #include <linux/mutex.h>
62 #else
63 #include <liblustre.h>
64 #endif
65
66 #include <obd.h>
67 #include <obd_class.h>
68 #include <obd_support.h>
69 #include <lustre/lustre_idl.h>
70 #include <lustre_net.h>
71 #include <lustre_import.h>
72 #include <lustre_sec.h>
73
74 #include "gss_err.h"
75 #include "gss_internal.h"
76 #include "gss_api.h"
77 #include "gss_asn1.h"
78 #include "gss_krb5.h"
79
80 spinlock_t krb5_seq_lock = SPIN_LOCK_UNLOCKED;
81
82 struct krb5_enctype {
83         char           *ke_dispname;
84         char           *ke_enc_name;            /* linux tfm name */
85         char           *ke_hash_name;           /* linux tfm name */
86         int             ke_enc_mode;            /* linux tfm mode */
87         int             ke_hash_size;           /* checksum size */
88         int             ke_conf_size;           /* confounder size */
89         unsigned int    ke_hash_hmac:1;         /* is hmac? */
90 };
91
92 /*
93  * NOTE: for aes128-cts and aes256-cts, MIT implementation use CTS encryption.
94  * but currently we simply CBC with padding, because linux doesn't support CTS
95  * yet. this need to be fixed in the future.
96  */
97 static struct krb5_enctype enctypes[] = {
98         [ENCTYPE_DES_CBC_RAW] = {               /* des-cbc-md5 */
99                 "des-cbc-md5",
100                 "cbc(des)",
101                 "md5",
102                 0,
103                 16,
104                 8,
105                 0,
106         },
107         [ENCTYPE_DES3_CBC_RAW] = {              /* des3-hmac-sha1 */
108                 "des3-hmac-sha1",
109                 "cbc(des3_ede)",
110                 "hmac(sha1)",
111                 0,
112                 20,
113                 8,
114                 1,
115         },
116         [ENCTYPE_AES128_CTS_HMAC_SHA1_96] = {   /* aes128-cts */
117                 "aes128-cts-hmac-sha1-96",
118                 "cbc(aes)",
119                 "hmac(sha1)",
120                 0,
121                 12,
122                 16,
123                 1,
124         },
125         [ENCTYPE_AES256_CTS_HMAC_SHA1_96] = {   /* aes256-cts */
126                 "aes256-cts-hmac-sha1-96",
127                 "cbc(aes)",
128                 "hmac(sha1)",
129                 0,
130                 12,
131                 16,
132                 1,
133         },
134         [ENCTYPE_ARCFOUR_HMAC] = {              /* arcfour-hmac-md5 */
135                 "arcfour-hmac-md5",
136                 "ecb(arc4)",
137                 "hmac(md5)",
138                 0,
139                 16,
140                 8,
141                 1,
142         },
143 };
144
145 #define MAX_ENCTYPES    sizeof(enctypes)/sizeof(struct krb5_enctype)
146
147 static const char * enctype2str(__u32 enctype)
148 {
149         if (enctype < MAX_ENCTYPES && enctypes[enctype].ke_dispname)
150                 return enctypes[enctype].ke_dispname;
151
152         return "unknown";
153 }
154
155 static
156 int keyblock_init(struct krb5_keyblock *kb, char *alg_name, int alg_mode)
157 {
158         kb->kb_tfm = ll_crypto_alloc_blkcipher(alg_name, alg_mode, 0);
159         if (kb->kb_tfm == NULL) {
160                 CERROR("failed to alloc tfm: %s, mode %d\n",
161                        alg_name, alg_mode);
162                 return -1;
163         }
164
165         if (ll_crypto_blkcipher_setkey(kb->kb_tfm, kb->kb_key.data, kb->kb_key.len)) {
166                 CERROR("failed to set %s key, len %d\n",
167                        alg_name, kb->kb_key.len);
168                 return -1;
169         }
170
171         return 0;
172 }
173
174 static
175 int krb5_init_keys(struct krb5_ctx *kctx)
176 {
177         struct krb5_enctype *ke;
178
179         if (kctx->kc_enctype >= MAX_ENCTYPES ||
180             enctypes[kctx->kc_enctype].ke_hash_size == 0) {
181                 CERROR("unsupported enctype %x\n", kctx->kc_enctype);
182                 return -1;
183         }
184
185         ke = &enctypes[kctx->kc_enctype];
186
187         /* tfm arc4 is stateful, user should alloc-use-free by his own */
188         if (kctx->kc_enctype != ENCTYPE_ARCFOUR_HMAC &&
189             keyblock_init(&kctx->kc_keye, ke->ke_enc_name, ke->ke_enc_mode))
190                 return -1;
191
192         /* tfm hmac is stateful, user should alloc-use-free by his own */
193         if (ke->ke_hash_hmac == 0 &&
194             keyblock_init(&kctx->kc_keyi, ke->ke_enc_name, ke->ke_enc_mode))
195                 return -1;
196         if (ke->ke_hash_hmac == 0 &&
197             keyblock_init(&kctx->kc_keyc, ke->ke_enc_name, ke->ke_enc_mode))
198                 return -1;
199
200         return 0;
201 }
202
203 static
204 void keyblock_free(struct krb5_keyblock *kb)
205 {
206         rawobj_free(&kb->kb_key);
207         if (kb->kb_tfm)
208                 ll_crypto_free_blkcipher(kb->kb_tfm);
209 }
210
211 static
212 int keyblock_dup(struct krb5_keyblock *new, struct krb5_keyblock *kb)
213 {
214         return rawobj_dup(&new->kb_key, &kb->kb_key);
215 }
216
217 static
218 int get_bytes(char **ptr, const char *end, void *res, int len)
219 {
220         char *p, *q;
221         p = *ptr;
222         q = p + len;
223         if (q > end || q < p)
224                 return -1;
225         memcpy(res, p, len);
226         *ptr = q;
227         return 0;
228 }
229
230 static
231 int get_rawobj(char **ptr, const char *end, rawobj_t *res)
232 {
233         char   *p, *q;
234         __u32   len;
235
236         p = *ptr;
237         if (get_bytes(&p, end, &len, sizeof(len)))
238                 return -1;
239
240         q = p + len;
241         if (q > end || q < p)
242                 return -1;
243
244         OBD_ALLOC(res->data, len);
245         if (!res->data)
246                 return -1;
247
248         res->len = len;
249         memcpy(res->data, p, len);
250         *ptr = q;
251         return 0;
252 }
253
254 static
255 int get_keyblock(char **ptr, const char *end,
256                  struct krb5_keyblock *kb, __u32 keysize)
257 {
258         char *buf;
259
260         OBD_ALLOC(buf, keysize);
261         if (buf == NULL)
262                 return -1;
263
264         if (get_bytes(ptr, end, buf, keysize)) {
265                 OBD_FREE(buf, keysize);
266                 return -1;
267         }
268
269         kb->kb_key.len = keysize;
270         kb->kb_key.data = buf;
271         return 0;
272 }
273
274 static
275 void delete_context_kerberos(struct krb5_ctx *kctx)
276 {
277         rawobj_free(&kctx->kc_mech_used);
278
279         keyblock_free(&kctx->kc_keye);
280         keyblock_free(&kctx->kc_keyi);
281         keyblock_free(&kctx->kc_keyc);
282 }
283
284 static
285 __u32 import_context_rfc1964(struct krb5_ctx *kctx, char *p, char *end)
286 {
287         unsigned int    tmp_uint, keysize;
288
289         /* seed_init flag */
290         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
291                 goto out_err;
292         kctx->kc_seed_init = (tmp_uint != 0);
293
294         /* seed */
295         if (get_bytes(&p, end, kctx->kc_seed, sizeof(kctx->kc_seed)))
296                 goto out_err;
297
298         /* sign/seal algorithm, not really used now */
299         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
300             get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
301                 goto out_err;
302
303         /* end time */
304         if (get_bytes(&p, end, &kctx->kc_endtime, sizeof(kctx->kc_endtime)))
305                 goto out_err;
306
307         /* seq send */
308         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
309                 goto out_err;
310         kctx->kc_seq_send = tmp_uint;
311
312         /* mech oid */
313         if (get_rawobj(&p, end, &kctx->kc_mech_used))
314                 goto out_err;
315
316         /* old style enc/seq keys in format:
317          *   - enctype (u32)
318          *   - keysize (u32)
319          *   - keydata
320          * we decompose them to fit into the new context
321          */
322
323         /* enc key */
324         if (get_bytes(&p, end, &kctx->kc_enctype, sizeof(kctx->kc_enctype)))
325                 goto out_err;
326
327         if (get_bytes(&p, end, &keysize, sizeof(keysize)))
328                 goto out_err;
329
330         if (get_keyblock(&p, end, &kctx->kc_keye, keysize))
331                 goto out_err;
332
333         /* seq key */
334         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
335             tmp_uint != kctx->kc_enctype)
336                 goto out_err;
337
338         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
339             tmp_uint != keysize)
340                 goto out_err;
341
342         if (get_keyblock(&p, end, &kctx->kc_keyc, keysize))
343                 goto out_err;
344
345         /* old style fallback */
346         if (keyblock_dup(&kctx->kc_keyi, &kctx->kc_keyc))
347                 goto out_err;
348
349         if (p != end)
350                 goto out_err;
351
352         CDEBUG(D_SEC, "succesfully imported rfc1964 context\n");
353         return 0;
354 out_err:
355         return GSS_S_FAILURE;
356 }
357
358 /* Flags for version 2 context flags */
359 #define KRB5_CTX_FLAG_INITIATOR         0x00000001
360 #define KRB5_CTX_FLAG_CFX               0x00000002
361 #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
362
363 static
364 __u32 import_context_rfc4121(struct krb5_ctx *kctx, char *p, char *end)
365 {
366         unsigned int    tmp_uint, keysize;
367
368         /* end time */
369         if (get_bytes(&p, end, &kctx->kc_endtime, sizeof(kctx->kc_endtime)))
370                 goto out_err;
371
372         /* flags */
373         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
374                 goto out_err;
375
376         if (tmp_uint & KRB5_CTX_FLAG_INITIATOR)
377                 kctx->kc_initiate = 1;
378         if (tmp_uint & KRB5_CTX_FLAG_CFX)
379                 kctx->kc_cfx = 1;
380         if (tmp_uint & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY)
381                 kctx->kc_have_acceptor_subkey = 1;
382
383         /* seq send */
384         if (get_bytes(&p, end, &kctx->kc_seq_send, sizeof(kctx->kc_seq_send)))
385                 goto out_err;
386
387         /* enctype */
388         if (get_bytes(&p, end, &kctx->kc_enctype, sizeof(kctx->kc_enctype)))
389                 goto out_err;
390
391         /* size of each key */
392         if (get_bytes(&p, end, &keysize, sizeof(keysize)))
393                 goto out_err;
394
395         /* number of keys - should always be 3 */
396         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
397                 goto out_err;
398
399         if (tmp_uint != 3) {
400                 CERROR("Invalid number of keys: %u\n", tmp_uint);
401                 goto out_err;
402         }
403
404         /* ke */
405         if (get_keyblock(&p, end, &kctx->kc_keye, keysize))
406                 goto out_err;
407         /* ki */
408         if (get_keyblock(&p, end, &kctx->kc_keyi, keysize))
409                 goto out_err;
410         /* ki */
411         if (get_keyblock(&p, end, &kctx->kc_keyc, keysize))
412                 goto out_err;
413
414         CDEBUG(D_SEC, "succesfully imported v2 context\n");
415         return 0;
416 out_err:
417         return GSS_S_FAILURE;
418 }
419
420 /*
421  * The whole purpose here is trying to keep user level gss context parsing
422  * from nfs-utils unchanged as possible as we can, they are not quite mature
423  * yet, and many stuff still not clear, like heimdal etc.
424  */
425 static
426 __u32 gss_import_sec_context_kerberos(rawobj_t *inbuf,
427                                       struct gss_ctx *gctx)
428 {
429         struct krb5_ctx *kctx;
430         char            *p = (char *) inbuf->data;
431         char            *end = (char *) (inbuf->data + inbuf->len);
432         unsigned int     tmp_uint, rc;
433
434         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint))) {
435                 CERROR("Fail to read version\n");
436                 return GSS_S_FAILURE;
437         }
438
439         /* only support 0, 1 for the moment */
440         if (tmp_uint > 2) {
441                 CERROR("Invalid version %u\n", tmp_uint);
442                 return GSS_S_FAILURE;
443         }
444
445         OBD_ALLOC_PTR(kctx);
446         if (!kctx)
447                 return GSS_S_FAILURE;
448
449         if (tmp_uint == 0 || tmp_uint == 1) {
450                 kctx->kc_initiate = tmp_uint;
451                 rc = import_context_rfc1964(kctx, p, end);
452         } else {
453                 rc = import_context_rfc4121(kctx, p, end);
454         }
455
456         if (rc == 0)
457                 rc = krb5_init_keys(kctx);
458
459         if (rc) {
460                 delete_context_kerberos(kctx);
461                 OBD_FREE_PTR(kctx);
462
463                 return GSS_S_FAILURE;
464         }
465
466         gctx->internal_ctx_id = kctx;
467         return GSS_S_COMPLETE;
468 }
469
470 static
471 __u32 gss_copy_reverse_context_kerberos(struct gss_ctx *gctx,
472                                         struct gss_ctx *gctx_new)
473 {
474         struct krb5_ctx *kctx = gctx->internal_ctx_id;
475         struct krb5_ctx *knew;
476
477         OBD_ALLOC_PTR(knew);
478         if (!knew)
479                 return GSS_S_FAILURE;
480
481         knew->kc_initiate = kctx->kc_initiate ? 0 : 1;
482         knew->kc_cfx = kctx->kc_cfx;
483         knew->kc_seed_init = kctx->kc_seed_init;
484         knew->kc_have_acceptor_subkey = kctx->kc_have_acceptor_subkey;
485         knew->kc_endtime = kctx->kc_endtime;
486
487         memcpy(knew->kc_seed, kctx->kc_seed, sizeof(kctx->kc_seed));
488         knew->kc_seq_send = kctx->kc_seq_recv;
489         knew->kc_seq_recv = kctx->kc_seq_send;
490         knew->kc_enctype = kctx->kc_enctype;
491
492         if (rawobj_dup(&knew->kc_mech_used, &kctx->kc_mech_used))
493                 goto out_err;
494
495         if (keyblock_dup(&knew->kc_keye, &kctx->kc_keye))
496                 goto out_err;
497         if (keyblock_dup(&knew->kc_keyi, &kctx->kc_keyi))
498                 goto out_err;
499         if (keyblock_dup(&knew->kc_keyc, &kctx->kc_keyc))
500                 goto out_err;
501         if (krb5_init_keys(knew))
502                 goto out_err;
503
504         gctx_new->internal_ctx_id = knew;
505         CDEBUG(D_SEC, "succesfully copied reverse context\n");
506         return GSS_S_COMPLETE;
507
508 out_err:
509         delete_context_kerberos(knew);
510         OBD_FREE_PTR(knew);
511         return GSS_S_FAILURE;
512 }
513
514 static
515 __u32 gss_inquire_context_kerberos(struct gss_ctx *gctx,
516                                    unsigned long  *endtime)
517 {
518         struct krb5_ctx *kctx = gctx->internal_ctx_id;
519
520         *endtime = (unsigned long) ((__u32) kctx->kc_endtime);
521         return GSS_S_COMPLETE;
522 }
523
524 static
525 void gss_delete_sec_context_kerberos(void *internal_ctx)
526 {
527         struct krb5_ctx *kctx = internal_ctx;
528
529         delete_context_kerberos(kctx);
530         OBD_FREE_PTR(kctx);
531 }
532
533 static
534 void buf_to_sg(struct scatterlist *sg, char *ptr, int len)
535 {
536         sg->page = virt_to_page(ptr);
537         sg->offset = offset_in_page(ptr);
538         sg->length = len;
539 }
540
541 static
542 __u32 krb5_encrypt(struct ll_crypto_cipher *tfm,
543                    int decrypt,
544                    void * iv,
545                    void * in,
546                    void * out,
547                    int length)
548 {
549         struct blkcipher_desc desc;
550         struct scatterlist    sg;
551         __u8 local_iv[16] = {0};
552         __u32 ret = -EINVAL;
553
554         LASSERT(tfm);
555         desc.tfm  = tfm;
556         desc.info = local_iv;
557         desc.flags= 0;
558
559         if (length % ll_crypto_blkcipher_blocksize(tfm) != 0) {
560                 CERROR("output length %d mismatch blocksize %d\n",
561                        length, ll_crypto_blkcipher_blocksize(tfm));
562                 goto out;
563         }
564
565         if (ll_crypto_blkcipher_ivsize(tfm) > 16) {
566                 CERROR("iv size too large %d\n", ll_crypto_blkcipher_ivsize(tfm));
567                 goto out;
568         }
569
570         if (iv)
571                 memcpy(local_iv, iv, ll_crypto_blkcipher_ivsize(tfm));
572
573         memcpy(out, in, length);
574         buf_to_sg(&sg, out, length);
575
576         if (decrypt)
577                 ret = ll_crypto_blkcipher_decrypt_iv(&desc, &sg, &sg, length);
578         else
579                 ret = ll_crypto_blkcipher_encrypt_iv(&desc, &sg, &sg, length);
580
581 out:
582         return(ret);
583 }
584
585 static inline
586 int krb5_digest_hmac(struct ll_crypto_hash *tfm,
587                      rawobj_t *key,
588                      struct krb5_header *khdr,
589                      int msgcnt, rawobj_t *msgs,
590                      rawobj_t *cksum)
591 #ifdef HAVE_ASYNC_BLOCK_CIPHER
592 {
593         struct hash_desc   desc;
594         struct scatterlist sg[1];
595         int                i;
596
597         ll_crypto_hash_setkey(tfm, key->data, key->len);
598         desc.tfm  = tfm;
599         desc.flags= 0;
600
601         ll_crypto_hash_init(&desc);
602
603         for (i = 0; i < msgcnt; i++) {
604                 if (msgs[i].len == 0)
605                         continue;
606                 buf_to_sg(sg, (char *) msgs[i].data, msgs[i].len);
607                 ll_crypto_hash_update(&desc, sg, msgs[i].len);
608         }
609
610         if (khdr) {
611                 buf_to_sg(sg, (char *) khdr, sizeof(*khdr));
612                 ll_crypto_hash_update(&desc, sg, sizeof(*khdr));
613         }
614
615         return ll_crypto_hash_final(&desc, cksum->data);
616 }
617 #else /* HAVE_ASYNC_BLOCK_CIPHER */
618 {
619         struct scatterlist sg[1];
620         __u32              keylen = key->len, i;
621
622         crypto_hmac_init(tfm, key->data, &keylen);
623
624         for (i = 0; i < msgcnt; i++) {
625                 if (msgs[i].len == 0)
626                         continue;
627                 buf_to_sg(sg, (char *) msgs[i].data, msgs[i].len);
628                 crypto_hmac_update(tfm, sg, 1);
629         }
630
631         if (khdr) {
632                 buf_to_sg(sg, (char *) khdr, sizeof(*khdr));
633                 crypto_hmac_update(tfm, sg, 1);
634         }
635
636         crypto_hmac_final(tfm, key->data, &keylen, cksum->data);
637         return 0;
638 }
639 #endif /* HAVE_ASYNC_BLOCK_CIPHER */
640
641 static inline
642 int krb5_digest_norm(struct ll_crypto_hash *tfm,
643                      struct krb5_keyblock *kb,
644                      struct krb5_header *khdr,
645                      int msgcnt, rawobj_t *msgs,
646                      rawobj_t *cksum)
647 {
648         struct hash_desc   desc;
649         struct scatterlist sg[1];
650         int                i;
651
652         LASSERT(kb->kb_tfm);
653         desc.tfm  = tfm;
654         desc.flags= 0;
655
656         ll_crypto_hash_init(&desc);
657
658         for (i = 0; i < msgcnt; i++) {
659                 if (msgs[i].len == 0)
660                         continue;
661                 buf_to_sg(sg, (char *) msgs[i].data, msgs[i].len);
662                 ll_crypto_hash_update(&desc, sg, msgs[i].len);
663         }
664
665         if (khdr) {
666                 buf_to_sg(sg, (char *) khdr, sizeof(*khdr));
667                 ll_crypto_hash_update(&desc, sg, sizeof(*khdr));
668         }
669
670         ll_crypto_hash_final(&desc, cksum->data);
671
672         return krb5_encrypt(kb->kb_tfm, 0, NULL, cksum->data,
673                             cksum->data, cksum->len);
674 }
675
676 /*
677  * compute (keyed/keyless) checksum against the plain text which appended
678  * with krb5 wire token header.
679  */
680 static
681 __s32 krb5_make_checksum(__u32 enctype,
682                          struct krb5_keyblock *kb,
683                          struct krb5_header *khdr,
684                          int msgcnt, rawobj_t *msgs,
685                          rawobj_t *cksum)
686 {
687         struct krb5_enctype   *ke = &enctypes[enctype];
688         struct ll_crypto_hash *tfm;
689         __u32                  code = GSS_S_FAILURE;
690         int                    rc;
691
692         if (!(tfm = ll_crypto_alloc_hash(ke->ke_hash_name, 0, 0))) {
693                 CERROR("failed to alloc TFM: %s\n", ke->ke_hash_name);
694                 return GSS_S_FAILURE;
695         }
696
697         cksum->len = ll_crypto_hash_digestsize(tfm);
698         OBD_ALLOC(cksum->data, cksum->len);
699         if (!cksum->data) {
700                 cksum->len = 0;
701                 goto out_tfm;
702         }
703
704         if (ke->ke_hash_hmac)
705                 rc = krb5_digest_hmac(tfm, &kb->kb_key,
706                                       khdr, msgcnt, msgs, cksum);
707         else
708                 rc = krb5_digest_norm(tfm, kb,
709                                       khdr, msgcnt, msgs, cksum);
710
711         if (rc == 0)
712                 code = GSS_S_COMPLETE;
713 out_tfm:
714         ll_crypto_free_hash(tfm);
715         return code;
716 }
717
718 static
719 __u32 gss_get_mic_kerberos(struct gss_ctx *gctx,
720                            int msgcnt,
721                            rawobj_t *msgs,
722                            rawobj_t *token)
723 {
724         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
725         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
726         struct krb5_header  *khdr;
727         unsigned char        acceptor_flag;
728         rawobj_t             cksum = RAWOBJ_EMPTY;
729         __u32                rc = GSS_S_FAILURE;
730
731         acceptor_flag = kctx->kc_initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
732
733         /* fill krb5 header */
734         LASSERT(token->len >= sizeof(*khdr));
735         khdr = (struct krb5_header *) token->data;
736
737         khdr->kh_tok_id = cpu_to_be16(KG_TOK_MIC_MSG);
738         khdr->kh_flags = acceptor_flag;
739         khdr->kh_filler = 0xff;
740         khdr->kh_ec = cpu_to_be16(0xffff);
741         khdr->kh_rrc = cpu_to_be16(0xffff);
742         spin_lock(&krb5_seq_lock);
743         khdr->kh_seq = cpu_to_be64(kctx->kc_seq_send++);
744         spin_unlock(&krb5_seq_lock);
745
746         /* checksum */
747         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyc,
748                                khdr, msgcnt, msgs, &cksum))
749                 goto out_err;
750
751         LASSERT(cksum.len >= ke->ke_hash_size);
752         LASSERT(token->len >= sizeof(*khdr) + ke->ke_hash_size);
753         memcpy(khdr + 1, cksum.data + cksum.len - ke->ke_hash_size,
754                ke->ke_hash_size);
755
756         token->len = sizeof(*khdr) + ke->ke_hash_size;
757         rc = GSS_S_COMPLETE;
758 out_err:
759         rawobj_free(&cksum);
760         return rc;
761 }
762
763 static
764 __u32 gss_verify_mic_kerberos(struct gss_ctx *gctx,
765                               int msgcnt,
766                               rawobj_t *msgs,
767                               rawobj_t *token)
768 {
769         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
770         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
771         struct krb5_header  *khdr;
772         unsigned char        acceptor_flag;
773         rawobj_t             cksum = RAWOBJ_EMPTY;
774         __u32                rc = GSS_S_FAILURE;
775
776         acceptor_flag = kctx->kc_initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
777
778         if (token->len < sizeof(*khdr)) {
779                 CERROR("short signature: %u\n", token->len);
780                 return GSS_S_DEFECTIVE_TOKEN;
781         }
782
783         khdr = (struct krb5_header *) token->data;
784
785         /* sanity checks */
786         if (be16_to_cpu(khdr->kh_tok_id) != KG_TOK_MIC_MSG) {
787                 CERROR("bad token id\n");
788                 return GSS_S_DEFECTIVE_TOKEN;
789         }
790         if ((khdr->kh_flags & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
791                 CERROR("bad direction flag\n");
792                 return GSS_S_BAD_SIG;
793         }
794         if (khdr->kh_filler != 0xff) {
795                 CERROR("bad filler\n");
796                 return GSS_S_DEFECTIVE_TOKEN;
797         }
798         if (be16_to_cpu(khdr->kh_ec) != 0xffff ||
799             be16_to_cpu(khdr->kh_rrc) != 0xffff) {
800                 CERROR("bad EC or RRC\n");
801                 return GSS_S_DEFECTIVE_TOKEN;
802         }
803
804         if (token->len < sizeof(*khdr) + ke->ke_hash_size) {
805                 CERROR("short signature: %u, require %d\n",
806                        token->len, (int) sizeof(*khdr) + ke->ke_hash_size);
807                 goto out;
808         }
809
810         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyc,
811                                khdr, msgcnt, msgs, &cksum))
812                 return GSS_S_FAILURE;
813
814         LASSERT(cksum.len >= ke->ke_hash_size);
815         if (memcmp(khdr + 1, cksum.data + cksum.len - ke->ke_hash_size,
816                    ke->ke_hash_size)) {
817                 CERROR("checksum mismatch\n");
818                 rc = GSS_S_BAD_SIG;
819                 goto out;
820         }
821
822         rc = GSS_S_COMPLETE;
823 out:
824         rawobj_free(&cksum);
825         return rc;
826 }
827
828 static
829 int add_padding(rawobj_t *msg, int msg_buflen, int blocksize)
830 {
831         int padding;
832
833         padding = (blocksize - (msg->len & (blocksize - 1))) &
834                   (blocksize - 1);
835         if (!padding)
836                 return 0;
837
838         if (msg->len + padding > msg_buflen) {
839                 CERROR("bufsize %u too small: datalen %u, padding %u\n",
840                         msg_buflen, msg->len, padding);
841                 return -EINVAL;
842         }
843
844         memset(msg->data + msg->len, padding, padding);
845         msg->len += padding;
846         return 0;
847 }
848
849 static
850 int krb5_encrypt_rawobjs(struct ll_crypto_cipher *tfm,
851                          int mode_ecb,
852                          int inobj_cnt,
853                          rawobj_t *inobjs,
854                          rawobj_t *outobj,
855                          int enc)
856 {
857         struct blkcipher_desc desc;
858         struct scatterlist    src, dst;
859         __u8                  local_iv[16] = {0}, *buf;
860         __u32                 datalen = 0;
861         int                   i, rc;
862         ENTRY;
863
864         buf = outobj->data;
865         desc.tfm  = tfm;
866         desc.info = local_iv;
867         desc.flags = 0;
868
869         for (i = 0; i < inobj_cnt; i++) {
870                 LASSERT(buf + inobjs[i].len <= outobj->data + outobj->len);
871
872                 buf_to_sg(&src, inobjs[i].data, inobjs[i].len);
873                 buf_to_sg(&dst, buf, outobj->len - datalen);
874
875                 if (mode_ecb) {
876                         if (enc)
877                                 rc = ll_crypto_blkcipher_encrypt(
878                                         &desc, &dst, &src, src.length);
879                         else
880                                 rc = ll_crypto_blkcipher_decrypt(
881                                         &desc, &dst, &src, src.length);
882                 } else {
883                         if (enc)
884                                 rc = ll_crypto_blkcipher_encrypt_iv(
885                                         &desc, &dst, &src, src.length);
886                         else
887                                 rc = ll_crypto_blkcipher_decrypt_iv(
888                                         &desc, &dst, &src, src.length);
889                 }
890
891                 if (rc) {
892                         CERROR("encrypt error %d\n", rc);
893                         RETURN(rc);
894                 }
895
896                 datalen += inobjs[i].len;
897                 buf += inobjs[i].len;
898         }
899
900         outobj->len = datalen;
901         RETURN(0);
902 }
903
904 static
905 __u32 gss_wrap_kerberos(struct gss_ctx *gctx,
906                         rawobj_t *gsshdr,
907                         rawobj_t *msg,
908                         int msg_buflen,
909                         rawobj_t *token)
910 {
911         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
912         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
913         struct krb5_header  *khdr;
914         unsigned char        acceptor_flag;
915         int                  blocksize;
916         rawobj_t             cksum = RAWOBJ_EMPTY;
917         rawobj_t             data_desc[4], cipher;
918         __u8                 conf[GSS_MAX_CIPHER_BLOCK];
919         int                  enc_rc = 0;
920
921         LASSERT(ke);
922         LASSERT(ke->ke_conf_size <= GSS_MAX_CIPHER_BLOCK);
923         LASSERT(kctx->kc_keye.kb_tfm == NULL ||
924                 ke->ke_conf_size >=
925                 ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm));
926
927         /*
928          * final token format:
929          * ---------------------------------------------------
930          * | krb5 header | cipher text | checksum (16 bytes) |
931          * ---------------------------------------------------
932          */
933
934         /* fill krb5 header */
935         LASSERT(token->len >= sizeof(*khdr));
936         khdr = (struct krb5_header *) token->data;
937         acceptor_flag = kctx->kc_initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
938
939         khdr->kh_tok_id = cpu_to_be16(KG_TOK_WRAP_MSG);
940         khdr->kh_flags = acceptor_flag | FLAG_WRAP_CONFIDENTIAL;
941         khdr->kh_filler = 0xff;
942         khdr->kh_ec = cpu_to_be16(0);
943         khdr->kh_rrc = cpu_to_be16(0);
944         spin_lock(&krb5_seq_lock);
945         khdr->kh_seq = cpu_to_be64(kctx->kc_seq_send++);
946         spin_unlock(&krb5_seq_lock);
947
948         /* generate confounder */
949         get_random_bytes(conf, ke->ke_conf_size);
950
951         /* get encryption blocksize. note kc_keye might not associated with
952          * a tfm, currently only for arcfour-hmac */
953         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
954                 LASSERT(kctx->kc_keye.kb_tfm == NULL);
955                 blocksize = 1;
956         } else {
957                 LASSERT(kctx->kc_keye.kb_tfm);
958                 blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
959         }
960         LASSERT(blocksize <= ke->ke_conf_size);
961
962         /* padding the message */
963         if (add_padding(msg, msg_buflen, blocksize))
964                 return GSS_S_FAILURE;
965
966         /*
967          * clear text layout for checksum:
968          * ------------------------------------------------------
969          * | confounder | gss header | clear msgs | krb5 header |
970          * ------------------------------------------------------
971          */
972         data_desc[0].data = conf;
973         data_desc[0].len = ke->ke_conf_size;
974         data_desc[1].data = gsshdr->data;
975         data_desc[1].len = gsshdr->len;
976         data_desc[2].data = msg->data;
977         data_desc[2].len = msg->len;
978         data_desc[3].data = (__u8 *) khdr;
979         data_desc[3].len = sizeof(*khdr);
980
981         /* compute checksum */
982         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyi,
983                                khdr, 4, data_desc, &cksum))
984                 return GSS_S_FAILURE;
985         LASSERT(cksum.len >= ke->ke_hash_size);
986
987         /*
988          * clear text layout for encryption:
989          * -----------------------------------------
990          * | confounder | clear msgs | krb5 header |
991          * -----------------------------------------
992          */
993         data_desc[0].data = conf;
994         data_desc[0].len = ke->ke_conf_size;
995         data_desc[1].data = msg->data;
996         data_desc[1].len = msg->len;
997         data_desc[2].data = (__u8 *) khdr;
998         data_desc[2].len = sizeof(*khdr);
999
1000         /* cipher text will be directly inplace */
1001         cipher.data = (__u8 *) (khdr + 1);
1002         cipher.len = token->len - sizeof(*khdr);
1003         LASSERT(cipher.len >= ke->ke_conf_size + msg->len + sizeof(*khdr));
1004
1005         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1006                 rawobj_t                 arc4_keye;
1007                 struct ll_crypto_cipher *arc4_tfm;
1008
1009                 if (krb5_make_checksum(ENCTYPE_ARCFOUR_HMAC, &kctx->kc_keyi,
1010                                        NULL, 1, &cksum, &arc4_keye)) {
1011                         CERROR("failed to obtain arc4 enc key\n");
1012                         GOTO(arc4_out, enc_rc = -EACCES);
1013                 }
1014
1015                 arc4_tfm = ll_crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
1016                 if (arc4_tfm == NULL) {
1017                         CERROR("failed to alloc tfm arc4 in ECB mode\n");
1018                         GOTO(arc4_out_key, enc_rc = -EACCES);
1019                 }
1020
1021                 if (ll_crypto_blkcipher_setkey(arc4_tfm, arc4_keye.data,
1022                                                arc4_keye.len)) {
1023                         CERROR("failed to set arc4 key, len %d\n",
1024                                arc4_keye.len);
1025                         GOTO(arc4_out_tfm, enc_rc = -EACCES);
1026                 }
1027
1028                 enc_rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
1029                                               3, data_desc, &cipher, 1);
1030 arc4_out_tfm:
1031                 ll_crypto_free_blkcipher(arc4_tfm);
1032 arc4_out_key:
1033                 rawobj_free(&arc4_keye);
1034 arc4_out:
1035                 do {} while(0); /* just to avoid compile warning */
1036         } else {
1037                 enc_rc = krb5_encrypt_rawobjs(kctx->kc_keye.kb_tfm, 0,
1038                                               3, data_desc, &cipher, 1);
1039         }
1040
1041         if (enc_rc != 0) {
1042                 rawobj_free(&cksum);
1043                 return GSS_S_FAILURE;
1044         }
1045
1046         /* fill in checksum */
1047         LASSERT(token->len >= sizeof(*khdr) + cipher.len + ke->ke_hash_size);
1048         memcpy((char *)(khdr + 1) + cipher.len,
1049                cksum.data + cksum.len - ke->ke_hash_size,
1050                ke->ke_hash_size);
1051         rawobj_free(&cksum);
1052
1053         /* final token length */
1054         token->len = sizeof(*khdr) + cipher.len + ke->ke_hash_size;
1055         return GSS_S_COMPLETE;
1056 }
1057
1058 static
1059 __u32 gss_unwrap_kerberos(struct gss_ctx  *gctx,
1060                           rawobj_t        *gsshdr,
1061                           rawobj_t        *token,
1062                           rawobj_t        *msg)
1063 {
1064         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
1065         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
1066         struct krb5_header  *khdr;
1067         unsigned char        acceptor_flag;
1068         unsigned char       *tmpbuf;
1069         int                  blocksize, bodysize;
1070         rawobj_t             cksum = RAWOBJ_EMPTY;
1071         rawobj_t             cipher_in, plain_out;
1072         rawobj_t             hash_objs[3];
1073         __u32                rc = GSS_S_FAILURE, enc_rc = 0;
1074
1075         LASSERT(ke);
1076
1077         acceptor_flag = kctx->kc_initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
1078
1079         if (token->len < sizeof(*khdr)) {
1080                 CERROR("short signature: %u\n", token->len);
1081                 return GSS_S_DEFECTIVE_TOKEN;
1082         }
1083
1084         khdr = (struct krb5_header *) token->data;
1085
1086         /* sanity check header */
1087         if (be16_to_cpu(khdr->kh_tok_id) != KG_TOK_WRAP_MSG) {
1088                 CERROR("bad token id\n");
1089                 return GSS_S_DEFECTIVE_TOKEN;
1090         }
1091         if ((khdr->kh_flags & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
1092                 CERROR("bad direction flag\n");
1093                 return GSS_S_BAD_SIG;
1094         }
1095         if ((khdr->kh_flags & FLAG_WRAP_CONFIDENTIAL) == 0) {
1096                 CERROR("missing confidential flag\n");
1097                 return GSS_S_BAD_SIG;
1098         }
1099         if (khdr->kh_filler != 0xff) {
1100                 CERROR("bad filler\n");
1101                 return GSS_S_DEFECTIVE_TOKEN;
1102         }
1103         if (be16_to_cpu(khdr->kh_ec) != 0x0 ||
1104             be16_to_cpu(khdr->kh_rrc) != 0x0) {
1105                 CERROR("bad EC or RRC\n");
1106                 return GSS_S_DEFECTIVE_TOKEN;
1107         }
1108
1109         /* block size */
1110         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1111                 LASSERT(kctx->kc_keye.kb_tfm == NULL);
1112                 blocksize = 1;
1113         } else {
1114                 LASSERT(kctx->kc_keye.kb_tfm);
1115                 blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
1116         }
1117
1118         /* expected token layout:
1119          * ----------------------------------------
1120          * | krb5 header | cipher text | checksum |
1121          * ----------------------------------------
1122          */
1123         bodysize = token->len - sizeof(*khdr) - ke->ke_hash_size;
1124
1125         if (bodysize % blocksize) {
1126                 CERROR("odd bodysize %d\n", bodysize);
1127                 return GSS_S_DEFECTIVE_TOKEN;
1128         }
1129
1130         if (bodysize <= ke->ke_conf_size + sizeof(*khdr)) {
1131                 CERROR("incomplete token: bodysize %d\n", bodysize);
1132                 return GSS_S_DEFECTIVE_TOKEN;
1133         }
1134
1135         if (msg->len < bodysize - ke->ke_conf_size - sizeof(*khdr)) {
1136                 CERROR("buffer too small: %u, require %d\n",
1137                        msg->len, bodysize - ke->ke_conf_size);
1138                 return GSS_S_FAILURE;
1139         }
1140
1141         /* decrypting */
1142         OBD_ALLOC(tmpbuf, bodysize);
1143         if (!tmpbuf)
1144                 return GSS_S_FAILURE;
1145
1146         cipher_in.data = (__u8 *) (khdr + 1);
1147         cipher_in.len = bodysize;
1148         plain_out.data = tmpbuf;
1149         plain_out.len = bodysize;
1150
1151         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1152                 rawobj_t                 arc4_keye;
1153                 struct ll_crypto_cipher *arc4_tfm;
1154
1155                 cksum.data = token->data + token->len - ke->ke_hash_size;
1156                 cksum.len = ke->ke_hash_size;
1157
1158                 if (krb5_make_checksum(ENCTYPE_ARCFOUR_HMAC, &kctx->kc_keyi,
1159                                        NULL, 1, &cksum, &arc4_keye)) {
1160                         CERROR("failed to obtain arc4 enc key\n");
1161                         GOTO(arc4_out, enc_rc = -EACCES);
1162                 }
1163
1164                 arc4_tfm = ll_crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
1165                 if (arc4_tfm == NULL) {
1166                         CERROR("failed to alloc tfm arc4 in ECB mode\n");
1167                         GOTO(arc4_out_key, enc_rc = -EACCES);
1168                 }
1169
1170                 if (ll_crypto_blkcipher_setkey(arc4_tfm,
1171                                          arc4_keye.data, arc4_keye.len)) {
1172                         CERROR("failed to set arc4 key, len %d\n",
1173                                arc4_keye.len);
1174                         GOTO(arc4_out_tfm, enc_rc = -EACCES);
1175                 }
1176
1177                 enc_rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
1178                                               1, &cipher_in, &plain_out, 0);
1179 arc4_out_tfm:
1180                 ll_crypto_free_blkcipher(arc4_tfm);
1181 arc4_out_key:
1182                 rawobj_free(&arc4_keye);
1183 arc4_out:
1184                 cksum = RAWOBJ_EMPTY;
1185         } else {
1186                 enc_rc = krb5_encrypt_rawobjs(kctx->kc_keye.kb_tfm, 0,
1187                                               1, &cipher_in, &plain_out, 0);
1188         }
1189
1190         if (enc_rc != 0) {
1191                 CERROR("error decrypt\n");
1192                 goto out_free;
1193         }
1194         LASSERT(plain_out.len == bodysize);
1195
1196         /* expected clear text layout:
1197          * -----------------------------------------
1198          * | confounder | clear msgs | krb5 header |
1199          * -----------------------------------------
1200          */
1201
1202         /* verify krb5 header in token is not modified */
1203         if (memcmp(khdr, plain_out.data + plain_out.len - sizeof(*khdr),
1204                    sizeof(*khdr))) {
1205                 CERROR("decrypted krb5 header mismatch\n");
1206                 goto out_free;
1207         }
1208
1209         /* verify checksum, compose clear text as layout:
1210          * ------------------------------------------------------
1211          * | confounder | gss header | clear msgs | krb5 header |
1212          * ------------------------------------------------------
1213          */
1214         hash_objs[0].len = ke->ke_conf_size;
1215         hash_objs[0].data = plain_out.data;
1216         hash_objs[1].len = gsshdr->len;
1217         hash_objs[1].data = gsshdr->data;
1218         hash_objs[2].len = plain_out.len - ke->ke_conf_size;
1219         hash_objs[2].data = plain_out.data + ke->ke_conf_size;
1220         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyi,
1221                                khdr, 3, hash_objs, &cksum))
1222                 goto out_free;
1223
1224         LASSERT(cksum.len >= ke->ke_hash_size);
1225         if (memcmp((char *)(khdr + 1) + bodysize,
1226                    cksum.data + cksum.len - ke->ke_hash_size,
1227                    ke->ke_hash_size)) {
1228                 CERROR("cksum mismatch\n");
1229                 goto out_free;
1230         }
1231
1232         msg->len =  bodysize - ke->ke_conf_size - sizeof(*khdr);
1233         memcpy(msg->data, tmpbuf + ke->ke_conf_size, msg->len);
1234
1235         rc = GSS_S_COMPLETE;
1236 out_free:
1237         OBD_FREE(tmpbuf, bodysize);
1238         rawobj_free(&cksum);
1239         return rc;
1240 }
1241
1242 static
1243 __u32 gss_plain_encrypt_kerberos(struct gss_ctx  *ctx,
1244                                  int              decrypt,
1245                                  int              length,
1246                                  void            *in_buf,
1247                                  void            *out_buf)
1248 {
1249         struct krb5_ctx        *kctx = ctx->internal_ctx_id;
1250         __u32                   rc;
1251
1252         rc = krb5_encrypt(kctx->kc_keye.kb_tfm, decrypt,
1253                           NULL, in_buf, out_buf, length);
1254         if (rc)
1255                 CERROR("plain encrypt error: %d\n", rc);
1256
1257         return rc;
1258 }
1259
1260 int gss_display_kerberos(struct gss_ctx        *ctx,
1261                          char                  *buf,
1262                          int                    bufsize)
1263 {
1264         struct krb5_ctx    *kctx = ctx->internal_ctx_id;
1265         int                 written;
1266
1267         written = snprintf(buf, bufsize, "krb5 (%s)",
1268                            enctype2str(kctx->kc_enctype));
1269         return written;
1270 }
1271
1272 static struct gss_api_ops gss_kerberos_ops = {
1273         .gss_import_sec_context     = gss_import_sec_context_kerberos,
1274         .gss_copy_reverse_context   = gss_copy_reverse_context_kerberos,
1275         .gss_inquire_context        = gss_inquire_context_kerberos,
1276         .gss_get_mic                = gss_get_mic_kerberos,
1277         .gss_verify_mic             = gss_verify_mic_kerberos,
1278         .gss_wrap                   = gss_wrap_kerberos,
1279         .gss_unwrap                 = gss_unwrap_kerberos,
1280         .gss_plain_encrypt          = gss_plain_encrypt_kerberos,
1281         .gss_delete_sec_context     = gss_delete_sec_context_kerberos,
1282         .gss_display                = gss_display_kerberos,
1283 };
1284
1285 static struct subflavor_desc gss_kerberos_sfs[] = {
1286         {
1287                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5N,
1288                 .sf_qop         = 0,
1289                 .sf_service     = SPTLRPC_SVC_NULL,
1290                 .sf_name        = "krb5n"
1291         },
1292         {
1293                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5A,
1294                 .sf_qop         = 0,
1295                 .sf_service     = SPTLRPC_SVC_AUTH,
1296                 .sf_name        = "krb5a"
1297         },
1298         {
1299                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5I,
1300                 .sf_qop         = 0,
1301                 .sf_service     = SPTLRPC_SVC_INTG,
1302                 .sf_name        = "krb5i"
1303         },
1304         {
1305                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5P,
1306                 .sf_qop         = 0,
1307                 .sf_service     = SPTLRPC_SVC_PRIV,
1308                 .sf_name        = "krb5p"
1309         },
1310 };
1311
1312 /*
1313  * currently we leave module owner NULL
1314  */
1315 static struct gss_api_mech gss_kerberos_mech = {
1316         .gm_owner       = NULL, /*THIS_MODULE, */
1317         .gm_name        = "krb5",
1318         .gm_oid         = (rawobj_t)
1319                                 {9, "\052\206\110\206\367\022\001\002\002"},
1320         .gm_ops         = &gss_kerberos_ops,
1321         .gm_sf_num      = 4,
1322         .gm_sfs         = gss_kerberos_sfs,
1323 };
1324
1325 int __init init_kerberos_module(void)
1326 {
1327         int status;
1328
1329         status = lgss_mech_register(&gss_kerberos_mech);
1330         if (status)
1331                 CERROR("Failed to register kerberos gss mechanism!\n");
1332         return status;
1333 }
1334
1335 void __exit cleanup_kerberos_module(void)
1336 {
1337         lgss_mech_unregister(&gss_kerberos_mech);
1338 }