Whamcloud - gitweb
LU-7243 misc: update Intel copyright messages 2015
[fs/lustre-release.git] / lustre / ptlrpc / gss / gss_krb5_mech.c
1 /*
2  * Modifications for Lustre
3  *
4  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5  *
6  * Copyright (c) 2011, 2015, Intel Corporation.
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 #define DEBUG_SUBSYSTEM S_SEC
52 #include <linux/init.h>
53 #include <linux/module.h>
54 #include <linux/slab.h>
55 #include <linux/crypto.h>
56 #include <linux/mutex.h>
57
58 #include <obd.h>
59 #include <obd_class.h>
60 #include <obd_support.h>
61 #include <lustre/lustre_idl.h>
62 #include <lustre_net.h>
63 #include <lustre_import.h>
64 #include <lustre_sec.h>
65
66 #include "gss_err.h"
67 #include "gss_internal.h"
68 #include "gss_api.h"
69 #include "gss_asn1.h"
70 #include "gss_krb5.h"
71
72 static spinlock_t krb5_seq_lock;
73
74 struct krb5_enctype {
75         char           *ke_dispname;
76         char           *ke_enc_name;            /* linux tfm name */
77         char           *ke_hash_name;           /* linux tfm name */
78         int             ke_enc_mode;            /* linux tfm mode */
79         int             ke_hash_size;           /* checksum size */
80         int             ke_conf_size;           /* confounder size */
81         unsigned int    ke_hash_hmac:1;         /* is hmac? */
82 };
83
84 /*
85  * NOTE: for aes128-cts and aes256-cts, MIT implementation use CTS encryption.
86  * but currently we simply CBC with padding, because linux doesn't support CTS
87  * yet. this need to be fixed in the future.
88  */
89 static struct krb5_enctype enctypes[] = {
90         [ENCTYPE_DES_CBC_RAW] = {               /* des-cbc-md5 */
91                 "des-cbc-md5",
92                 "cbc(des)",
93                 "md5",
94                 0,
95                 16,
96                 8,
97                 0,
98         },
99         [ENCTYPE_DES3_CBC_RAW] = {              /* des3-hmac-sha1 */
100                 "des3-hmac-sha1",
101                 "cbc(des3_ede)",
102                 "hmac(sha1)",
103                 0,
104                 20,
105                 8,
106                 1,
107         },
108         [ENCTYPE_AES128_CTS_HMAC_SHA1_96] = {   /* aes128-cts */
109                 "aes128-cts-hmac-sha1-96",
110                 "cbc(aes)",
111                 "hmac(sha1)",
112                 0,
113                 12,
114                 16,
115                 1,
116         },
117         [ENCTYPE_AES256_CTS_HMAC_SHA1_96] = {   /* aes256-cts */
118                 "aes256-cts-hmac-sha1-96",
119                 "cbc(aes)",
120                 "hmac(sha1)",
121                 0,
122                 12,
123                 16,
124                 1,
125         },
126         [ENCTYPE_ARCFOUR_HMAC] = {              /* arcfour-hmac-md5 */
127                 "arcfour-hmac-md5",
128                 "ecb(arc4)",
129                 "hmac(md5)",
130                 0,
131                 16,
132                 8,
133                 1,
134         },
135 };
136
137 #define MAX_ENCTYPES    sizeof(enctypes)/sizeof(struct krb5_enctype)
138
139 static const char * enctype2str(__u32 enctype)
140 {
141         if (enctype < MAX_ENCTYPES && enctypes[enctype].ke_dispname)
142                 return enctypes[enctype].ke_dispname;
143
144         return "unknown";
145 }
146
147 static
148 int keyblock_init(struct krb5_keyblock *kb, char *alg_name, int alg_mode)
149 {
150         kb->kb_tfm = crypto_alloc_blkcipher(alg_name, alg_mode, 0);
151         if (IS_ERR(kb->kb_tfm)) {
152                 CERROR("failed to alloc tfm: %s, mode %d\n",
153                        alg_name, alg_mode);
154                 return -1;
155         }
156
157         if (crypto_blkcipher_setkey(kb->kb_tfm, kb->kb_key.data, kb->kb_key.len)) {
158                 CERROR("failed to set %s key, len %d\n",
159                        alg_name, kb->kb_key.len);
160                 return -1;
161         }
162
163         return 0;
164 }
165
166 static
167 int krb5_init_keys(struct krb5_ctx *kctx)
168 {
169         struct krb5_enctype *ke;
170
171         if (kctx->kc_enctype >= MAX_ENCTYPES ||
172             enctypes[kctx->kc_enctype].ke_hash_size == 0) {
173                 CERROR("unsupported enctype %x\n", kctx->kc_enctype);
174                 return -1;
175         }
176
177         ke = &enctypes[kctx->kc_enctype];
178
179         /* tfm arc4 is stateful, user should alloc-use-free by his own */
180         if (kctx->kc_enctype != ENCTYPE_ARCFOUR_HMAC &&
181             keyblock_init(&kctx->kc_keye, ke->ke_enc_name, ke->ke_enc_mode))
182                 return -1;
183
184         /* tfm hmac is stateful, user should alloc-use-free by his own */
185         if (ke->ke_hash_hmac == 0 &&
186             keyblock_init(&kctx->kc_keyi, ke->ke_enc_name, ke->ke_enc_mode))
187                 return -1;
188         if (ke->ke_hash_hmac == 0 &&
189             keyblock_init(&kctx->kc_keyc, ke->ke_enc_name, ke->ke_enc_mode))
190                 return -1;
191
192         return 0;
193 }
194
195 static
196 void keyblock_free(struct krb5_keyblock *kb)
197 {
198         rawobj_free(&kb->kb_key);
199         if (kb->kb_tfm)
200                 crypto_free_blkcipher(kb->kb_tfm);
201 }
202
203 static
204 int keyblock_dup(struct krb5_keyblock *new, struct krb5_keyblock *kb)
205 {
206         return rawobj_dup(&new->kb_key, &kb->kb_key);
207 }
208
209 static
210 int get_bytes(char **ptr, const char *end, void *res, int len)
211 {
212         char *p, *q;
213         p = *ptr;
214         q = p + len;
215         if (q > end || q < p)
216                 return -1;
217         memcpy(res, p, len);
218         *ptr = q;
219         return 0;
220 }
221
222 static
223 int get_rawobj(char **ptr, const char *end, rawobj_t *res)
224 {
225         char   *p, *q;
226         __u32   len;
227
228         p = *ptr;
229         if (get_bytes(&p, end, &len, sizeof(len)))
230                 return -1;
231
232         q = p + len;
233         if (q > end || q < p)
234                 return -1;
235
236         OBD_ALLOC_LARGE(res->data, len);
237         if (!res->data)
238                 return -1;
239
240         res->len = len;
241         memcpy(res->data, p, len);
242         *ptr = q;
243         return 0;
244 }
245
246 static
247 int get_keyblock(char **ptr, const char *end,
248                  struct krb5_keyblock *kb, __u32 keysize)
249 {
250         char *buf;
251
252         OBD_ALLOC_LARGE(buf, keysize);
253         if (buf == NULL)
254                 return -1;
255
256         if (get_bytes(ptr, end, buf, keysize)) {
257                 OBD_FREE_LARGE(buf, keysize);
258                 return -1;
259         }
260
261         kb->kb_key.len = keysize;
262         kb->kb_key.data = buf;
263         return 0;
264 }
265
266 static
267 void delete_context_kerberos(struct krb5_ctx *kctx)
268 {
269         rawobj_free(&kctx->kc_mech_used);
270
271         keyblock_free(&kctx->kc_keye);
272         keyblock_free(&kctx->kc_keyi);
273         keyblock_free(&kctx->kc_keyc);
274 }
275
276 static
277 __u32 import_context_rfc1964(struct krb5_ctx *kctx, char *p, char *end)
278 {
279         unsigned int    tmp_uint, keysize;
280
281         /* seed_init flag */
282         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
283                 goto out_err;
284         kctx->kc_seed_init = (tmp_uint != 0);
285
286         /* seed */
287         if (get_bytes(&p, end, kctx->kc_seed, sizeof(kctx->kc_seed)))
288                 goto out_err;
289
290         /* sign/seal algorithm, not really used now */
291         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
292             get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
293                 goto out_err;
294
295         /* end time */
296         if (get_bytes(&p, end, &kctx->kc_endtime, sizeof(kctx->kc_endtime)))
297                 goto out_err;
298
299         /* seq send */
300         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
301                 goto out_err;
302         kctx->kc_seq_send = tmp_uint;
303
304         /* mech oid */
305         if (get_rawobj(&p, end, &kctx->kc_mech_used))
306                 goto out_err;
307
308         /* old style enc/seq keys in format:
309          *   - enctype (u32)
310          *   - keysize (u32)
311          *   - keydata
312          * we decompose them to fit into the new context
313          */
314
315         /* enc key */
316         if (get_bytes(&p, end, &kctx->kc_enctype, sizeof(kctx->kc_enctype)))
317                 goto out_err;
318
319         if (get_bytes(&p, end, &keysize, sizeof(keysize)))
320                 goto out_err;
321
322         if (get_keyblock(&p, end, &kctx->kc_keye, keysize))
323                 goto out_err;
324
325         /* seq key */
326         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
327             tmp_uint != kctx->kc_enctype)
328                 goto out_err;
329
330         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
331             tmp_uint != keysize)
332                 goto out_err;
333
334         if (get_keyblock(&p, end, &kctx->kc_keyc, keysize))
335                 goto out_err;
336
337         /* old style fallback */
338         if (keyblock_dup(&kctx->kc_keyi, &kctx->kc_keyc))
339                 goto out_err;
340
341         if (p != end)
342                 goto out_err;
343
344         CDEBUG(D_SEC, "successfully imported rfc1964 context\n");
345         return 0;
346 out_err:
347         return GSS_S_FAILURE;
348 }
349
350 /* Flags for version 2 context flags */
351 #define KRB5_CTX_FLAG_INITIATOR         0x00000001
352 #define KRB5_CTX_FLAG_CFX               0x00000002
353 #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
354
355 static
356 __u32 import_context_rfc4121(struct krb5_ctx *kctx, char *p, char *end)
357 {
358         unsigned int    tmp_uint, keysize;
359
360         /* end time */
361         if (get_bytes(&p, end, &kctx->kc_endtime, sizeof(kctx->kc_endtime)))
362                 goto out_err;
363
364         /* flags */
365         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
366                 goto out_err;
367
368         if (tmp_uint & KRB5_CTX_FLAG_INITIATOR)
369                 kctx->kc_initiate = 1;
370         if (tmp_uint & KRB5_CTX_FLAG_CFX)
371                 kctx->kc_cfx = 1;
372         if (tmp_uint & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY)
373                 kctx->kc_have_acceptor_subkey = 1;
374
375         /* seq send */
376         if (get_bytes(&p, end, &kctx->kc_seq_send, sizeof(kctx->kc_seq_send)))
377                 goto out_err;
378
379         /* enctype */
380         if (get_bytes(&p, end, &kctx->kc_enctype, sizeof(kctx->kc_enctype)))
381                 goto out_err;
382
383         /* size of each key */
384         if (get_bytes(&p, end, &keysize, sizeof(keysize)))
385                 goto out_err;
386
387         /* number of keys - should always be 3 */
388         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
389                 goto out_err;
390
391         if (tmp_uint != 3) {
392                 CERROR("Invalid number of keys: %u\n", tmp_uint);
393                 goto out_err;
394         }
395
396         /* ke */
397         if (get_keyblock(&p, end, &kctx->kc_keye, keysize))
398                 goto out_err;
399         /* ki */
400         if (get_keyblock(&p, end, &kctx->kc_keyi, keysize))
401                 goto out_err;
402         /* ki */
403         if (get_keyblock(&p, end, &kctx->kc_keyc, keysize))
404                 goto out_err;
405
406         CDEBUG(D_SEC, "successfully imported v2 context\n");
407         return 0;
408 out_err:
409         return GSS_S_FAILURE;
410 }
411
412 /*
413  * The whole purpose here is trying to keep user level gss context parsing
414  * from nfs-utils unchanged as possible as we can, they are not quite mature
415  * yet, and many stuff still not clear, like heimdal etc.
416  */
417 static
418 __u32 gss_import_sec_context_kerberos(rawobj_t *inbuf,
419                                       struct gss_ctx *gctx)
420 {
421         struct krb5_ctx *kctx;
422         char            *p = (char *) inbuf->data;
423         char            *end = (char *) (inbuf->data + inbuf->len);
424         unsigned int     tmp_uint, rc;
425
426         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint))) {
427                 CERROR("Fail to read version\n");
428                 return GSS_S_FAILURE;
429         }
430
431         /* only support 0, 1 for the moment */
432         if (tmp_uint > 2) {
433                 CERROR("Invalid version %u\n", tmp_uint);
434                 return GSS_S_FAILURE;
435         }
436
437         OBD_ALLOC_PTR(kctx);
438         if (!kctx)
439                 return GSS_S_FAILURE;
440
441         if (tmp_uint == 0 || tmp_uint == 1) {
442                 kctx->kc_initiate = tmp_uint;
443                 rc = import_context_rfc1964(kctx, p, end);
444         } else {
445                 rc = import_context_rfc4121(kctx, p, end);
446         }
447
448         if (rc == 0)
449                 rc = krb5_init_keys(kctx);
450
451         if (rc) {
452                 delete_context_kerberos(kctx);
453                 OBD_FREE_PTR(kctx);
454
455                 return GSS_S_FAILURE;
456         }
457
458         gctx->internal_ctx_id = kctx;
459         return GSS_S_COMPLETE;
460 }
461
462 static
463 __u32 gss_copy_reverse_context_kerberos(struct gss_ctx *gctx,
464                                         struct gss_ctx *gctx_new)
465 {
466         struct krb5_ctx *kctx = gctx->internal_ctx_id;
467         struct krb5_ctx *knew;
468
469         OBD_ALLOC_PTR(knew);
470         if (!knew)
471                 return GSS_S_FAILURE;
472
473         knew->kc_initiate = kctx->kc_initiate ? 0 : 1;
474         knew->kc_cfx = kctx->kc_cfx;
475         knew->kc_seed_init = kctx->kc_seed_init;
476         knew->kc_have_acceptor_subkey = kctx->kc_have_acceptor_subkey;
477         knew->kc_endtime = kctx->kc_endtime;
478
479         memcpy(knew->kc_seed, kctx->kc_seed, sizeof(kctx->kc_seed));
480         knew->kc_seq_send = kctx->kc_seq_recv;
481         knew->kc_seq_recv = kctx->kc_seq_send;
482         knew->kc_enctype = kctx->kc_enctype;
483
484         if (rawobj_dup(&knew->kc_mech_used, &kctx->kc_mech_used))
485                 goto out_err;
486
487         if (keyblock_dup(&knew->kc_keye, &kctx->kc_keye))
488                 goto out_err;
489         if (keyblock_dup(&knew->kc_keyi, &kctx->kc_keyi))
490                 goto out_err;
491         if (keyblock_dup(&knew->kc_keyc, &kctx->kc_keyc))
492                 goto out_err;
493         if (krb5_init_keys(knew))
494                 goto out_err;
495
496         gctx_new->internal_ctx_id = knew;
497         CDEBUG(D_SEC, "successfully copied reverse context\n");
498         return GSS_S_COMPLETE;
499
500 out_err:
501         delete_context_kerberos(knew);
502         OBD_FREE_PTR(knew);
503         return GSS_S_FAILURE;
504 }
505
506 static
507 __u32 gss_inquire_context_kerberos(struct gss_ctx *gctx,
508                                    unsigned long  *endtime)
509 {
510         struct krb5_ctx *kctx = gctx->internal_ctx_id;
511
512         *endtime = (unsigned long) ((__u32) kctx->kc_endtime);
513         return GSS_S_COMPLETE;
514 }
515
516 static
517 void gss_delete_sec_context_kerberos(void *internal_ctx)
518 {
519         struct krb5_ctx *kctx = internal_ctx;
520
521         delete_context_kerberos(kctx);
522         OBD_FREE_PTR(kctx);
523 }
524
525 static
526 void buf_to_sg(struct scatterlist *sg, void *ptr, int len)
527 {
528         sg_init_table(sg, 1);
529         sg_set_buf(sg, ptr, len);
530 }
531
532 static
533 __u32 krb5_encrypt(struct crypto_blkcipher *tfm,
534                    int decrypt,
535                    void * iv,
536                    void * in,
537                    void * out,
538                    int length)
539 {
540         struct blkcipher_desc desc;
541         struct scatterlist    sg;
542         __u8 local_iv[16] = {0};
543         __u32 ret = -EINVAL;
544
545         LASSERT(tfm);
546         desc.tfm  = tfm;
547         desc.info = local_iv;
548         desc.flags= 0;
549
550         if (length % crypto_blkcipher_blocksize(tfm) != 0) {
551                 CERROR("output length %d mismatch blocksize %d\n",
552                        length, crypto_blkcipher_blocksize(tfm));
553                 goto out;
554         }
555
556         if (crypto_blkcipher_ivsize(tfm) > 16) {
557                 CERROR("iv size too large %d\n", crypto_blkcipher_ivsize(tfm));
558                 goto out;
559         }
560
561         if (iv)
562                 memcpy(local_iv, iv, crypto_blkcipher_ivsize(tfm));
563
564         memcpy(out, in, length);
565         buf_to_sg(&sg, out, length);
566
567         if (decrypt)
568                 ret = crypto_blkcipher_decrypt_iv(&desc, &sg, &sg, length);
569         else
570                 ret = crypto_blkcipher_encrypt_iv(&desc, &sg, &sg, length);
571
572 out:
573         return(ret);
574 }
575
576 static inline
577 int krb5_digest_hmac(struct crypto_hash *tfm,
578                      rawobj_t *key,
579                      struct krb5_header *khdr,
580                      int msgcnt, rawobj_t *msgs,
581                      int iovcnt, lnet_kiov_t *iovs,
582                      rawobj_t *cksum)
583 {
584         struct hash_desc   desc;
585         struct scatterlist sg[1];
586         int                i;
587
588         crypto_hash_setkey(tfm, key->data, key->len);
589         desc.tfm  = tfm;
590         desc.flags= 0;
591
592         crypto_hash_init(&desc);
593
594         for (i = 0; i < msgcnt; i++) {
595                 if (msgs[i].len == 0)
596                         continue;
597                 buf_to_sg(sg, (char *) msgs[i].data, msgs[i].len);
598                 crypto_hash_update(&desc, sg, msgs[i].len);
599         }
600
601         for (i = 0; i < iovcnt; i++) {
602                 if (iovs[i].kiov_len == 0)
603                         continue;
604
605                 sg_init_table(sg, 1);
606                 sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
607                             iovs[i].kiov_offset);
608                 crypto_hash_update(&desc, sg, iovs[i].kiov_len);
609         }
610
611         if (khdr) {
612                 buf_to_sg(sg, (char *) khdr, sizeof(*khdr));
613                 crypto_hash_update(&desc, sg, sizeof(*khdr));
614         }
615
616         return crypto_hash_final(&desc, cksum->data);
617 }
618
619 static inline
620 int krb5_digest_norm(struct crypto_hash *tfm,
621                      struct krb5_keyblock *kb,
622                      struct krb5_header *khdr,
623                      int msgcnt, rawobj_t *msgs,
624                      int iovcnt, lnet_kiov_t *iovs,
625                      rawobj_t *cksum)
626 {
627         struct hash_desc   desc;
628         struct scatterlist sg[1];
629         int                i;
630
631         LASSERT(kb->kb_tfm);
632         desc.tfm  = tfm;
633         desc.flags= 0;
634
635         crypto_hash_init(&desc);
636
637         for (i = 0; i < msgcnt; i++) {
638                 if (msgs[i].len == 0)
639                         continue;
640                 buf_to_sg(sg, (char *) msgs[i].data, msgs[i].len);
641                 crypto_hash_update(&desc, sg, msgs[i].len);
642         }
643
644         for (i = 0; i < iovcnt; i++) {
645                 if (iovs[i].kiov_len == 0)
646                         continue;
647
648                 sg_init_table(sg, 1);
649                 sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
650                             iovs[i].kiov_offset);
651                 crypto_hash_update(&desc, sg, iovs[i].kiov_len);
652         }
653
654         if (khdr) {
655                 buf_to_sg(sg, (char *) khdr, sizeof(*khdr));
656                 crypto_hash_update(&desc, sg, sizeof(*khdr));
657         }
658
659         crypto_hash_final(&desc, cksum->data);
660
661         return krb5_encrypt(kb->kb_tfm, 0, NULL, cksum->data,
662                             cksum->data, cksum->len);
663 }
664
665 /*
666  * compute (keyed/keyless) checksum against the plain text which appended
667  * with krb5 wire token header.
668  */
669 static
670 __s32 krb5_make_checksum(__u32 enctype,
671                          struct krb5_keyblock *kb,
672                          struct krb5_header *khdr,
673                          int msgcnt, rawobj_t *msgs,
674                          int iovcnt, lnet_kiov_t *iovs,
675                          rawobj_t *cksum)
676 {
677         struct krb5_enctype   *ke = &enctypes[enctype];
678         struct crypto_hash    *tfm;
679         __u32                  code = GSS_S_FAILURE;
680         int                    rc;
681
682         if (!(tfm = crypto_alloc_hash(ke->ke_hash_name, 0, 0))) {
683                 CERROR("failed to alloc TFM: %s\n", ke->ke_hash_name);
684                 return GSS_S_FAILURE;
685         }
686
687         cksum->len = crypto_hash_digestsize(tfm);
688         OBD_ALLOC_LARGE(cksum->data, cksum->len);
689         if (!cksum->data) {
690                 cksum->len = 0;
691                 goto out_tfm;
692         }
693
694         if (ke->ke_hash_hmac)
695                 rc = krb5_digest_hmac(tfm, &kb->kb_key,
696                                       khdr, msgcnt, msgs, iovcnt, iovs, cksum);
697         else
698                 rc = krb5_digest_norm(tfm, kb,
699                                       khdr, msgcnt, msgs, iovcnt, iovs, cksum);
700
701         if (rc == 0)
702                 code = GSS_S_COMPLETE;
703 out_tfm:
704         crypto_free_hash(tfm);
705         return code;
706 }
707
708 static void fill_krb5_header(struct krb5_ctx *kctx,
709                              struct krb5_header *khdr,
710                              int privacy)
711 {
712         unsigned char acceptor_flag;
713
714         acceptor_flag = kctx->kc_initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
715
716         if (privacy) {
717                 khdr->kh_tok_id = cpu_to_be16(KG_TOK_WRAP_MSG);
718                 khdr->kh_flags = acceptor_flag | FLAG_WRAP_CONFIDENTIAL;
719                 khdr->kh_ec = cpu_to_be16(0);
720                 khdr->kh_rrc = cpu_to_be16(0);
721         } else {
722                 khdr->kh_tok_id = cpu_to_be16(KG_TOK_MIC_MSG);
723                 khdr->kh_flags = acceptor_flag;
724                 khdr->kh_ec = cpu_to_be16(0xffff);
725                 khdr->kh_rrc = cpu_to_be16(0xffff);
726         }
727
728         khdr->kh_filler = 0xff;
729         spin_lock(&krb5_seq_lock);
730         khdr->kh_seq = cpu_to_be64(kctx->kc_seq_send++);
731         spin_unlock(&krb5_seq_lock);
732 }
733
734 static __u32 verify_krb5_header(struct krb5_ctx *kctx,
735                                 struct krb5_header *khdr,
736                                 int privacy)
737 {
738         unsigned char acceptor_flag;
739         __u16         tok_id, ec_rrc;
740
741         acceptor_flag = kctx->kc_initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
742
743         if (privacy) {
744                 tok_id = KG_TOK_WRAP_MSG;
745                 ec_rrc = 0x0;
746         } else {
747                 tok_id = KG_TOK_MIC_MSG;
748                 ec_rrc = 0xffff;
749         }
750
751         /* sanity checks */
752         if (be16_to_cpu(khdr->kh_tok_id) != tok_id) {
753                 CERROR("bad token id\n");
754                 return GSS_S_DEFECTIVE_TOKEN;
755         }
756         if ((khdr->kh_flags & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
757                 CERROR("bad direction flag\n");
758                 return GSS_S_BAD_SIG;
759         }
760         if (privacy && (khdr->kh_flags & FLAG_WRAP_CONFIDENTIAL) == 0) {
761                 CERROR("missing confidential flag\n");
762                 return GSS_S_BAD_SIG;
763         }
764         if (khdr->kh_filler != 0xff) {
765                 CERROR("bad filler\n");
766                 return GSS_S_DEFECTIVE_TOKEN;
767         }
768         if (be16_to_cpu(khdr->kh_ec) != ec_rrc ||
769             be16_to_cpu(khdr->kh_rrc) != ec_rrc) {
770                 CERROR("bad EC or RRC\n");
771                 return GSS_S_DEFECTIVE_TOKEN;
772         }
773         return GSS_S_COMPLETE;
774 }
775
776 static
777 __u32 gss_get_mic_kerberos(struct gss_ctx *gctx,
778                            int msgcnt,
779                            rawobj_t *msgs,
780                            int iovcnt,
781                            lnet_kiov_t *iovs,
782                            rawobj_t *token)
783 {
784         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
785         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
786         struct krb5_header  *khdr;
787         rawobj_t             cksum = RAWOBJ_EMPTY;
788
789         /* fill krb5 header */
790         LASSERT(token->len >= sizeof(*khdr));
791         khdr = (struct krb5_header *) token->data;
792         fill_krb5_header(kctx, khdr, 0);
793
794         /* checksum */
795         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyc,
796                                khdr, msgcnt, msgs, iovcnt, iovs, &cksum))
797                 return GSS_S_FAILURE;
798
799         LASSERT(cksum.len >= ke->ke_hash_size);
800         LASSERT(token->len >= sizeof(*khdr) + ke->ke_hash_size);
801         memcpy(khdr + 1, cksum.data + cksum.len - ke->ke_hash_size,
802                ke->ke_hash_size);
803
804         token->len = sizeof(*khdr) + ke->ke_hash_size;
805         rawobj_free(&cksum);
806         return GSS_S_COMPLETE;
807 }
808
809 static
810 __u32 gss_verify_mic_kerberos(struct gss_ctx *gctx,
811                               int msgcnt,
812                               rawobj_t *msgs,
813                               int iovcnt,
814                               lnet_kiov_t *iovs,
815                               rawobj_t *token)
816 {
817         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
818         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
819         struct krb5_header  *khdr;
820         rawobj_t             cksum = RAWOBJ_EMPTY;
821         __u32                major;
822
823         if (token->len < sizeof(*khdr)) {
824                 CERROR("short signature: %u\n", token->len);
825                 return GSS_S_DEFECTIVE_TOKEN;
826         }
827
828         khdr = (struct krb5_header *) token->data;
829
830         major = verify_krb5_header(kctx, khdr, 0);
831         if (major != GSS_S_COMPLETE) {
832                 CERROR("bad krb5 header\n");
833                 return major;
834         }
835
836         if (token->len < sizeof(*khdr) + ke->ke_hash_size) {
837                 CERROR("short signature: %u, require %d\n",
838                        token->len, (int) sizeof(*khdr) + ke->ke_hash_size);
839                 return GSS_S_FAILURE;
840         }
841
842         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyc,
843                                khdr, msgcnt, msgs, iovcnt, iovs, &cksum)) {
844                 CERROR("failed to make checksum\n");
845                 return GSS_S_FAILURE;
846         }
847
848         LASSERT(cksum.len >= ke->ke_hash_size);
849         if (memcmp(khdr + 1, cksum.data + cksum.len - ke->ke_hash_size,
850                    ke->ke_hash_size)) {
851                 CERROR("checksum mismatch\n");
852                 rawobj_free(&cksum);
853                 return GSS_S_BAD_SIG;
854         }
855
856         rawobj_free(&cksum);
857         return GSS_S_COMPLETE;
858 }
859
860 static
861 int add_padding(rawobj_t *msg, int msg_buflen, int blocksize)
862 {
863         int padding;
864
865         padding = (blocksize - (msg->len & (blocksize - 1))) &
866                   (blocksize - 1);
867         if (!padding)
868                 return 0;
869
870         if (msg->len + padding > msg_buflen) {
871                 CERROR("bufsize %u too small: datalen %u, padding %u\n",
872                         msg_buflen, msg->len, padding);
873                 return -EINVAL;
874         }
875
876         memset(msg->data + msg->len, padding, padding);
877         msg->len += padding;
878         return 0;
879 }
880
881 static
882 int krb5_encrypt_rawobjs(struct crypto_blkcipher *tfm,
883                          int mode_ecb,
884                          int inobj_cnt,
885                          rawobj_t *inobjs,
886                          rawobj_t *outobj,
887                          int enc)
888 {
889         struct blkcipher_desc desc;
890         struct scatterlist    src, dst;
891         __u8                  local_iv[16] = {0}, *buf;
892         __u32                 datalen = 0;
893         int                   i, rc;
894         ENTRY;
895
896         buf = outobj->data;
897         desc.tfm  = tfm;
898         desc.info = local_iv;
899         desc.flags = 0;
900
901         for (i = 0; i < inobj_cnt; i++) {
902                 LASSERT(buf + inobjs[i].len <= outobj->data + outobj->len);
903
904                 buf_to_sg(&src, inobjs[i].data, inobjs[i].len);
905                 buf_to_sg(&dst, buf, outobj->len - datalen);
906
907                 if (mode_ecb) {
908                         if (enc)
909                                 rc = crypto_blkcipher_encrypt(
910                                         &desc, &dst, &src, src.length);
911                         else
912                                 rc = crypto_blkcipher_decrypt(
913                                         &desc, &dst, &src, src.length);
914                 } else {
915                         if (enc)
916                                 rc = crypto_blkcipher_encrypt_iv(
917                                         &desc, &dst, &src, src.length);
918                         else
919                                 rc = crypto_blkcipher_decrypt_iv(
920                                         &desc, &dst, &src, src.length);
921                 }
922
923                 if (rc) {
924                         CERROR("encrypt error %d\n", rc);
925                         RETURN(rc);
926                 }
927
928                 datalen += inobjs[i].len;
929                 buf += inobjs[i].len;
930         }
931
932         outobj->len = datalen;
933         RETURN(0);
934 }
935
936 /*
937  * if adj_nob != 0, we adjust desc->bd_nob to the actual cipher text size.
938  */
939 static
940 int krb5_encrypt_bulk(struct crypto_blkcipher *tfm,
941                       struct krb5_header *khdr,
942                       char *confounder,
943                       struct ptlrpc_bulk_desc *desc,
944                       rawobj_t *cipher,
945                       int adj_nob)
946 {
947         struct blkcipher_desc   ciph_desc;
948         __u8                    local_iv[16] = {0};
949         struct scatterlist      src, dst;
950         int                     blocksize, i, rc, nob = 0;
951
952         LASSERT(ptlrpc_is_bulk_desc_kiov(desc->bd_type));
953         LASSERT(desc->bd_iov_count);
954         LASSERT(GET_ENC_KIOV(desc));
955
956         blocksize = crypto_blkcipher_blocksize(tfm);
957         LASSERT(blocksize > 1);
958         LASSERT(cipher->len == blocksize + sizeof(*khdr));
959
960         ciph_desc.tfm  = tfm;
961         ciph_desc.info = local_iv;
962         ciph_desc.flags = 0;
963
964         /* encrypt confounder */
965         buf_to_sg(&src, confounder, blocksize);
966         buf_to_sg(&dst, cipher->data, blocksize);
967
968         rc = crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src, blocksize);
969         if (rc) {
970                 CERROR("error to encrypt confounder: %d\n", rc);
971                 return rc;
972         }
973
974         /* encrypt clear pages */
975         for (i = 0; i < desc->bd_iov_count; i++) {
976                 sg_init_table(&src, 1);
977                 sg_set_page(&src, BD_GET_KIOV(desc, i).kiov_page,
978                             (BD_GET_KIOV(desc, i).kiov_len +
979                                 blocksize - 1) &
980                             (~(blocksize - 1)),
981                             BD_GET_KIOV(desc, i).kiov_offset);
982                 if (adj_nob)
983                         nob += src.length;
984                 sg_init_table(&dst, 1);
985                 sg_set_page(&dst, BD_GET_ENC_KIOV(desc, i).kiov_page,
986                             src.length, src.offset);
987
988                 BD_GET_ENC_KIOV(desc, i).kiov_offset = dst.offset;
989                 BD_GET_ENC_KIOV(desc, i).kiov_len = dst.length;
990
991                 rc = crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src,
992                                                     src.length);
993                 if (rc) {
994                         CERROR("error to encrypt page: %d\n", rc);
995                         return rc;
996                 }
997         }
998
999         /* encrypt krb5 header */
1000         buf_to_sg(&src, khdr, sizeof(*khdr));
1001         buf_to_sg(&dst, cipher->data + blocksize, sizeof(*khdr));
1002
1003         rc = crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src,
1004                                          sizeof(*khdr));
1005         if (rc) {
1006                 CERROR("error to encrypt krb5 header: %d\n", rc);
1007                 return rc;
1008         }
1009
1010         if (adj_nob)
1011                 desc->bd_nob = nob;
1012
1013         return 0;
1014 }
1015
1016 /*
1017  * desc->bd_nob_transferred is the size of cipher text received.
1018  * desc->bd_nob is the target size of plain text supposed to be.
1019  *
1020  * if adj_nob != 0, we adjust each page's kiov_len to the actual
1021  * plain text size.
1022  * - for client read: we don't know data size for each page, so
1023  *   bd_iov[]->kiov_len is set to PAGE_SIZE, but actual data received might
1024  *   be smaller, so we need to adjust it according to
1025  *   bd_u.bd_kiov.bd_enc_vec[]->kiov_len.
1026  *   this means we DO NOT support the situation that server send an odd size
1027  *   data in a page which is not the last one.
1028  * - for server write: we knows exactly data size for each page being expected,
1029  *   thus kiov_len is accurate already, so we should not adjust it at all.
1030  *   and bd_u.bd_kiov.bd_enc_vec[]->kiov_len should be
1031  *   round_up(bd_iov[]->kiov_len) which
1032  *   should have been done by prep_bulk().
1033  */
1034 static
1035 int krb5_decrypt_bulk(struct crypto_blkcipher *tfm,
1036                       struct krb5_header *khdr,
1037                       struct ptlrpc_bulk_desc *desc,
1038                       rawobj_t *cipher,
1039                       rawobj_t *plain,
1040                       int adj_nob)
1041 {
1042         struct blkcipher_desc   ciph_desc;
1043         __u8                    local_iv[16] = {0};
1044         struct scatterlist      src, dst;
1045         int                     ct_nob = 0, pt_nob = 0;
1046         int                     blocksize, i, rc;
1047
1048         LASSERT(ptlrpc_is_bulk_desc_kiov(desc->bd_type));
1049         LASSERT(desc->bd_iov_count);
1050         LASSERT(GET_ENC_KIOV(desc));
1051         LASSERT(desc->bd_nob_transferred);
1052
1053         blocksize = crypto_blkcipher_blocksize(tfm);
1054         LASSERT(blocksize > 1);
1055         LASSERT(cipher->len == blocksize + sizeof(*khdr));
1056
1057         ciph_desc.tfm  = tfm;
1058         ciph_desc.info = local_iv;
1059         ciph_desc.flags = 0;
1060
1061         if (desc->bd_nob_transferred % blocksize) {
1062                 CERROR("odd transferred nob: %d\n", desc->bd_nob_transferred);
1063                 return -EPROTO;
1064         }
1065
1066         /* decrypt head (confounder) */
1067         buf_to_sg(&src, cipher->data, blocksize);
1068         buf_to_sg(&dst, plain->data, blocksize);
1069
1070         rc = crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src, blocksize);
1071         if (rc) {
1072                 CERROR("error to decrypt confounder: %d\n", rc);
1073                 return rc;
1074         }
1075
1076         for (i = 0; i < desc->bd_iov_count && ct_nob < desc->bd_nob_transferred;
1077              i++) {
1078                 if (BD_GET_ENC_KIOV(desc, i).kiov_offset % blocksize
1079                     != 0 ||
1080                     BD_GET_ENC_KIOV(desc, i).kiov_len % blocksize
1081                     != 0) {
1082                         CERROR("page %d: odd offset %u len %u, blocksize %d\n",
1083                                i, BD_GET_ENC_KIOV(desc, i).kiov_offset,
1084                                BD_GET_ENC_KIOV(desc, i).kiov_len,
1085                                blocksize);
1086                         return -EFAULT;
1087                 }
1088
1089                 if (adj_nob) {
1090                         if (ct_nob + BD_GET_ENC_KIOV(desc, i).kiov_len >
1091                             desc->bd_nob_transferred)
1092                                 BD_GET_ENC_KIOV(desc, i).kiov_len =
1093                                         desc->bd_nob_transferred - ct_nob;
1094
1095                         BD_GET_KIOV(desc, i).kiov_len =
1096                           BD_GET_ENC_KIOV(desc, i).kiov_len;
1097                         if (pt_nob + BD_GET_ENC_KIOV(desc, i).kiov_len >
1098                             desc->bd_nob)
1099                                 BD_GET_KIOV(desc, i).kiov_len =
1100                                   desc->bd_nob - pt_nob;
1101                 } else {
1102                         /* this should be guaranteed by LNET */
1103                         LASSERT(ct_nob + BD_GET_ENC_KIOV(desc, i).
1104                                 kiov_len <=
1105                                 desc->bd_nob_transferred);
1106                         LASSERT(BD_GET_KIOV(desc, i).kiov_len <=
1107                                 BD_GET_ENC_KIOV(desc, i).kiov_len);
1108                 }
1109
1110                 if (BD_GET_ENC_KIOV(desc, i).kiov_len == 0)
1111                         continue;
1112
1113                 sg_init_table(&src, 1);
1114                 sg_set_page(&src, BD_GET_ENC_KIOV(desc, i).kiov_page,
1115                             BD_GET_ENC_KIOV(desc, i).kiov_len,
1116                             BD_GET_ENC_KIOV(desc, i).kiov_offset);
1117                 dst = src;
1118                 if (BD_GET_KIOV(desc, i).kiov_len % blocksize == 0)
1119                         sg_assign_page(&dst,
1120                                        BD_GET_KIOV(desc, i).kiov_page);
1121
1122                 rc = crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src,
1123                                                  src.length);
1124                 if (rc) {
1125                         CERROR("error to decrypt page: %d\n", rc);
1126                         return rc;
1127                 }
1128
1129                 if (BD_GET_KIOV(desc, i).kiov_len % blocksize != 0) {
1130                         memcpy(page_address(BD_GET_KIOV(desc, i).kiov_page) +
1131                                BD_GET_KIOV(desc, i).kiov_offset,
1132                                page_address(BD_GET_ENC_KIOV(desc, i).
1133                                             kiov_page) +
1134                                BD_GET_KIOV(desc, i).kiov_offset,
1135                                BD_GET_KIOV(desc, i).kiov_len);
1136                 }
1137
1138                 ct_nob += BD_GET_ENC_KIOV(desc, i).kiov_len;
1139                 pt_nob += BD_GET_KIOV(desc, i).kiov_len;
1140         }
1141
1142         if (unlikely(ct_nob != desc->bd_nob_transferred)) {
1143                 CERROR("%d cipher text transferred but only %d decrypted\n",
1144                        desc->bd_nob_transferred, ct_nob);
1145                 return -EFAULT;
1146         }
1147
1148         if (unlikely(!adj_nob && pt_nob != desc->bd_nob)) {
1149                 CERROR("%d plain text expected but only %d received\n",
1150                        desc->bd_nob, pt_nob);
1151                 return -EFAULT;
1152         }
1153
1154         /* if needed, clear up the rest unused iovs */
1155         if (adj_nob)
1156                 while (i < desc->bd_iov_count)
1157                         BD_GET_KIOV(desc, i++).kiov_len = 0;
1158
1159         /* decrypt tail (krb5 header) */
1160         buf_to_sg(&src, cipher->data + blocksize, sizeof(*khdr));
1161         buf_to_sg(&dst, cipher->data + blocksize, sizeof(*khdr));
1162
1163         rc = crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src,
1164                                          sizeof(*khdr));
1165         if (rc) {
1166                 CERROR("error to decrypt tail: %d\n", rc);
1167                 return rc;
1168         }
1169
1170         if (memcmp(cipher->data + blocksize, khdr, sizeof(*khdr))) {
1171                 CERROR("krb5 header doesn't match\n");
1172                 return -EACCES;
1173         }
1174
1175         return 0;
1176 }
1177
1178 static
1179 __u32 gss_wrap_kerberos(struct gss_ctx *gctx,
1180                         rawobj_t *gsshdr,
1181                         rawobj_t *msg,
1182                         int msg_buflen,
1183                         rawobj_t *token)
1184 {
1185         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
1186         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
1187         struct krb5_header  *khdr;
1188         int                  blocksize;
1189         rawobj_t             cksum = RAWOBJ_EMPTY;
1190         rawobj_t             data_desc[3], cipher;
1191         __u8                 conf[GSS_MAX_CIPHER_BLOCK];
1192         int                  rc = 0;
1193
1194         LASSERT(ke);
1195         LASSERT(ke->ke_conf_size <= GSS_MAX_CIPHER_BLOCK);
1196         LASSERT(kctx->kc_keye.kb_tfm == NULL ||
1197                 ke->ke_conf_size >=
1198                 crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm));
1199
1200         /*
1201          * final token format:
1202          * ---------------------------------------------------
1203          * | krb5 header | cipher text | checksum (16 bytes) |
1204          * ---------------------------------------------------
1205          */
1206
1207         /* fill krb5 header */
1208         LASSERT(token->len >= sizeof(*khdr));
1209         khdr = (struct krb5_header *) token->data;
1210         fill_krb5_header(kctx, khdr, 1);
1211
1212         /* generate confounder */
1213         cfs_get_random_bytes(conf, ke->ke_conf_size);
1214
1215         /* get encryption blocksize. note kc_keye might not associated with
1216          * a tfm, currently only for arcfour-hmac */
1217         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1218                 LASSERT(kctx->kc_keye.kb_tfm == NULL);
1219                 blocksize = 1;
1220         } else {
1221                 LASSERT(kctx->kc_keye.kb_tfm);
1222                 blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
1223         }
1224         LASSERT(blocksize <= ke->ke_conf_size);
1225
1226         /* padding the message */
1227         if (add_padding(msg, msg_buflen, blocksize))
1228                 return GSS_S_FAILURE;
1229
1230         /*
1231          * clear text layout for checksum:
1232          * ------------------------------------------------------
1233          * | confounder | gss header | clear msgs | krb5 header |
1234          * ------------------------------------------------------
1235          */
1236         data_desc[0].data = conf;
1237         data_desc[0].len = ke->ke_conf_size;
1238         data_desc[1].data = gsshdr->data;
1239         data_desc[1].len = gsshdr->len;
1240         data_desc[2].data = msg->data;
1241         data_desc[2].len = msg->len;
1242
1243         /* compute checksum */
1244         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyi,
1245                                khdr, 3, data_desc, 0, NULL, &cksum))
1246                 return GSS_S_FAILURE;
1247         LASSERT(cksum.len >= ke->ke_hash_size);
1248
1249         /*
1250          * clear text layout for encryption:
1251          * -----------------------------------------
1252          * | confounder | clear msgs | krb5 header |
1253          * -----------------------------------------
1254          */
1255         data_desc[0].data = conf;
1256         data_desc[0].len = ke->ke_conf_size;
1257         data_desc[1].data = msg->data;
1258         data_desc[1].len = msg->len;
1259         data_desc[2].data = (__u8 *) khdr;
1260         data_desc[2].len = sizeof(*khdr);
1261
1262         /* cipher text will be directly inplace */
1263         cipher.data = (__u8 *) (khdr + 1);
1264         cipher.len = token->len - sizeof(*khdr);
1265         LASSERT(cipher.len >= ke->ke_conf_size + msg->len + sizeof(*khdr));
1266
1267         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1268                 rawobj_t                 arc4_keye;
1269                 struct crypto_blkcipher *arc4_tfm;
1270
1271                 if (krb5_make_checksum(ENCTYPE_ARCFOUR_HMAC, &kctx->kc_keyi,
1272                                        NULL, 1, &cksum, 0, NULL, &arc4_keye)) {
1273                         CERROR("failed to obtain arc4 enc key\n");
1274                         GOTO(arc4_out, rc = -EACCES);
1275                 }
1276
1277                 arc4_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
1278                 if (IS_ERR(arc4_tfm)) {
1279                         CERROR("failed to alloc tfm arc4 in ECB mode\n");
1280                         GOTO(arc4_out_key, rc = -EACCES);
1281                 }
1282
1283                 if (crypto_blkcipher_setkey(arc4_tfm, arc4_keye.data,
1284                                                arc4_keye.len)) {
1285                         CERROR("failed to set arc4 key, len %d\n",
1286                                arc4_keye.len);
1287                         GOTO(arc4_out_tfm, rc = -EACCES);
1288                 }
1289
1290                 rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
1291                                           3, data_desc, &cipher, 1);
1292 arc4_out_tfm:
1293                 crypto_free_blkcipher(arc4_tfm);
1294 arc4_out_key:
1295                 rawobj_free(&arc4_keye);
1296 arc4_out:
1297                 do {} while(0); /* just to avoid compile warning */
1298         } else {
1299                 rc = krb5_encrypt_rawobjs(kctx->kc_keye.kb_tfm, 0,
1300                                           3, data_desc, &cipher, 1);
1301         }
1302
1303         if (rc != 0) {
1304                 rawobj_free(&cksum);
1305                 return GSS_S_FAILURE;
1306         }
1307
1308         /* fill in checksum */
1309         LASSERT(token->len >= sizeof(*khdr) + cipher.len + ke->ke_hash_size);
1310         memcpy((char *)(khdr + 1) + cipher.len,
1311                cksum.data + cksum.len - ke->ke_hash_size,
1312                ke->ke_hash_size);
1313         rawobj_free(&cksum);
1314
1315         /* final token length */
1316         token->len = sizeof(*khdr) + cipher.len + ke->ke_hash_size;
1317         return GSS_S_COMPLETE;
1318 }
1319
1320 static
1321 __u32 gss_prep_bulk_kerberos(struct gss_ctx *gctx,
1322                              struct ptlrpc_bulk_desc *desc)
1323 {
1324         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
1325         int                  blocksize, i;
1326
1327         LASSERT(ptlrpc_is_bulk_desc_kiov(desc->bd_type));
1328         LASSERT(desc->bd_iov_count);
1329         LASSERT(GET_ENC_KIOV(desc));
1330         LASSERT(kctx->kc_keye.kb_tfm);
1331
1332         blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
1333
1334         for (i = 0; i < desc->bd_iov_count; i++) {
1335                 LASSERT(BD_GET_ENC_KIOV(desc, i).kiov_page);
1336                 /*
1337                  * offset should always start at page boundary of either
1338                  * client or server side.
1339                  */
1340                 if (BD_GET_KIOV(desc, i).kiov_offset & blocksize) {
1341                         CERROR("odd offset %d in page %d\n",
1342                                BD_GET_KIOV(desc, i).kiov_offset, i);
1343                         return GSS_S_FAILURE;
1344                 }
1345
1346                 BD_GET_ENC_KIOV(desc, i).kiov_offset =
1347                         BD_GET_KIOV(desc, i).kiov_offset;
1348                 BD_GET_ENC_KIOV(desc, i).kiov_len =
1349                         (BD_GET_KIOV(desc, i).kiov_len +
1350                          blocksize - 1) & (~(blocksize - 1));
1351         }
1352
1353         return GSS_S_COMPLETE;
1354 }
1355
1356 static
1357 __u32 gss_wrap_bulk_kerberos(struct gss_ctx *gctx,
1358                              struct ptlrpc_bulk_desc *desc,
1359                              rawobj_t *token, int adj_nob)
1360 {
1361         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
1362         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
1363         struct krb5_header  *khdr;
1364         int                  blocksize;
1365         rawobj_t             cksum = RAWOBJ_EMPTY;
1366         rawobj_t             data_desc[1], cipher;
1367         __u8                 conf[GSS_MAX_CIPHER_BLOCK];
1368         int                  rc = 0;
1369
1370         LASSERT(ptlrpc_is_bulk_desc_kiov(desc->bd_type));
1371         LASSERT(ke);
1372         LASSERT(ke->ke_conf_size <= GSS_MAX_CIPHER_BLOCK);
1373
1374         /*
1375          * final token format:
1376          * --------------------------------------------------
1377          * | krb5 header | head/tail cipher text | checksum |
1378          * --------------------------------------------------
1379          */
1380
1381         /* fill krb5 header */
1382         LASSERT(token->len >= sizeof(*khdr));
1383         khdr = (struct krb5_header *) token->data;
1384         fill_krb5_header(kctx, khdr, 1);
1385
1386         /* generate confounder */
1387         cfs_get_random_bytes(conf, ke->ke_conf_size);
1388
1389         /* get encryption blocksize. note kc_keye might not associated with
1390          * a tfm, currently only for arcfour-hmac */
1391         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1392                 LASSERT(kctx->kc_keye.kb_tfm == NULL);
1393                 blocksize = 1;
1394         } else {
1395                 LASSERT(kctx->kc_keye.kb_tfm);
1396                 blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
1397         }
1398
1399         /*
1400          * we assume the size of krb5_header (16 bytes) must be n * blocksize.
1401          * the bulk token size would be exactly (sizeof(krb5_header) +
1402          * blocksize + sizeof(krb5_header) + hashsize)
1403          */
1404         LASSERT(blocksize <= ke->ke_conf_size);
1405         LASSERT(sizeof(*khdr) >= blocksize && sizeof(*khdr) % blocksize == 0);
1406         LASSERT(token->len >= sizeof(*khdr) + blocksize + sizeof(*khdr) + 16);
1407
1408         /*
1409          * clear text layout for checksum:
1410          * ------------------------------------------
1411          * | confounder | clear pages | krb5 header |
1412          * ------------------------------------------
1413          */
1414         data_desc[0].data = conf;
1415         data_desc[0].len = ke->ke_conf_size;
1416
1417         /* compute checksum */
1418         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyi,
1419                                khdr, 1, data_desc,
1420                                desc->bd_iov_count, GET_KIOV(desc),
1421                                &cksum))
1422                 return GSS_S_FAILURE;
1423         LASSERT(cksum.len >= ke->ke_hash_size);
1424
1425         /*
1426          * clear text layout for encryption:
1427          * ------------------------------------------
1428          * | confounder | clear pages | krb5 header |
1429          * ------------------------------------------
1430          *        |              |             |
1431          *        ----------  (cipher pages)   |
1432          * result token:   |                   |
1433          * -------------------------------------------
1434          * | krb5 header | cipher text | cipher text |
1435          * -------------------------------------------
1436          */
1437         data_desc[0].data = conf;
1438         data_desc[0].len = ke->ke_conf_size;
1439
1440         cipher.data = (__u8 *) (khdr + 1);
1441         cipher.len = blocksize + sizeof(*khdr);
1442
1443         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1444                 LBUG();
1445                 rc = 0;
1446         } else {
1447                 rc = krb5_encrypt_bulk(kctx->kc_keye.kb_tfm, khdr,
1448                                        conf, desc, &cipher, adj_nob);
1449         }
1450
1451         if (rc != 0) {
1452                 rawobj_free(&cksum);
1453                 return GSS_S_FAILURE;
1454         }
1455
1456         /* fill in checksum */
1457         LASSERT(token->len >= sizeof(*khdr) + cipher.len + ke->ke_hash_size);
1458         memcpy((char *)(khdr + 1) + cipher.len,
1459                cksum.data + cksum.len - ke->ke_hash_size,
1460                ke->ke_hash_size);
1461         rawobj_free(&cksum);
1462
1463         /* final token length */
1464         token->len = sizeof(*khdr) + cipher.len + ke->ke_hash_size;
1465         return GSS_S_COMPLETE;
1466 }
1467
1468 static
1469 __u32 gss_unwrap_kerberos(struct gss_ctx  *gctx,
1470                           rawobj_t        *gsshdr,
1471                           rawobj_t        *token,
1472                           rawobj_t        *msg)
1473 {
1474         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
1475         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
1476         struct krb5_header  *khdr;
1477         unsigned char       *tmpbuf;
1478         int                  blocksize, bodysize;
1479         rawobj_t             cksum = RAWOBJ_EMPTY;
1480         rawobj_t             cipher_in, plain_out;
1481         rawobj_t             hash_objs[3];
1482         int                  rc = 0;
1483         __u32                major;
1484
1485         LASSERT(ke);
1486
1487         if (token->len < sizeof(*khdr)) {
1488                 CERROR("short signature: %u\n", token->len);
1489                 return GSS_S_DEFECTIVE_TOKEN;
1490         }
1491
1492         khdr = (struct krb5_header *) token->data;
1493
1494         major = verify_krb5_header(kctx, khdr, 1);
1495         if (major != GSS_S_COMPLETE) {
1496                 CERROR("bad krb5 header\n");
1497                 return major;
1498         }
1499
1500         /* block size */
1501         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1502                 LASSERT(kctx->kc_keye.kb_tfm == NULL);
1503                 blocksize = 1;
1504         } else {
1505                 LASSERT(kctx->kc_keye.kb_tfm);
1506                 blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
1507         }
1508
1509         /* expected token layout:
1510          * ----------------------------------------
1511          * | krb5 header | cipher text | checksum |
1512          * ----------------------------------------
1513          */
1514         bodysize = token->len - sizeof(*khdr) - ke->ke_hash_size;
1515
1516         if (bodysize % blocksize) {
1517                 CERROR("odd bodysize %d\n", bodysize);
1518                 return GSS_S_DEFECTIVE_TOKEN;
1519         }
1520
1521         if (bodysize <= ke->ke_conf_size + sizeof(*khdr)) {
1522                 CERROR("incomplete token: bodysize %d\n", bodysize);
1523                 return GSS_S_DEFECTIVE_TOKEN;
1524         }
1525
1526         if (msg->len < bodysize - ke->ke_conf_size - sizeof(*khdr)) {
1527                 CERROR("buffer too small: %u, require %d\n",
1528                        msg->len, bodysize - ke->ke_conf_size);
1529                 return GSS_S_FAILURE;
1530         }
1531
1532         /* decrypting */
1533         OBD_ALLOC_LARGE(tmpbuf, bodysize);
1534         if (!tmpbuf)
1535                 return GSS_S_FAILURE;
1536
1537         major = GSS_S_FAILURE;
1538
1539         cipher_in.data = (__u8 *) (khdr + 1);
1540         cipher_in.len = bodysize;
1541         plain_out.data = tmpbuf;
1542         plain_out.len = bodysize;
1543
1544         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1545                 rawobj_t                 arc4_keye;
1546                 struct crypto_blkcipher *arc4_tfm;
1547
1548                 cksum.data = token->data + token->len - ke->ke_hash_size;
1549                 cksum.len = ke->ke_hash_size;
1550
1551                 if (krb5_make_checksum(ENCTYPE_ARCFOUR_HMAC, &kctx->kc_keyi,
1552                                        NULL, 1, &cksum, 0, NULL, &arc4_keye)) {
1553                         CERROR("failed to obtain arc4 enc key\n");
1554                         GOTO(arc4_out, rc = -EACCES);
1555                 }
1556
1557                 arc4_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
1558                 if (IS_ERR(arc4_tfm)) {
1559                         CERROR("failed to alloc tfm arc4 in ECB mode\n");
1560                         GOTO(arc4_out_key, rc = -EACCES);
1561                 }
1562
1563                 if (crypto_blkcipher_setkey(arc4_tfm,
1564                                          arc4_keye.data, arc4_keye.len)) {
1565                         CERROR("failed to set arc4 key, len %d\n",
1566                                arc4_keye.len);
1567                         GOTO(arc4_out_tfm, rc = -EACCES);
1568                 }
1569
1570                 rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
1571                                           1, &cipher_in, &plain_out, 0);
1572 arc4_out_tfm:
1573                 crypto_free_blkcipher(arc4_tfm);
1574 arc4_out_key:
1575                 rawobj_free(&arc4_keye);
1576 arc4_out:
1577                 cksum = RAWOBJ_EMPTY;
1578         } else {
1579                 rc = krb5_encrypt_rawobjs(kctx->kc_keye.kb_tfm, 0,
1580                                           1, &cipher_in, &plain_out, 0);
1581         }
1582
1583         if (rc != 0) {
1584                 CERROR("error decrypt\n");
1585                 goto out_free;
1586         }
1587         LASSERT(plain_out.len == bodysize);
1588
1589         /* expected clear text layout:
1590          * -----------------------------------------
1591          * | confounder | clear msgs | krb5 header |
1592          * -----------------------------------------
1593          */
1594
1595         /* verify krb5 header in token is not modified */
1596         if (memcmp(khdr, plain_out.data + plain_out.len - sizeof(*khdr),
1597                    sizeof(*khdr))) {
1598                 CERROR("decrypted krb5 header mismatch\n");
1599                 goto out_free;
1600         }
1601
1602         /* verify checksum, compose clear text as layout:
1603          * ------------------------------------------------------
1604          * | confounder | gss header | clear msgs | krb5 header |
1605          * ------------------------------------------------------
1606          */
1607         hash_objs[0].len = ke->ke_conf_size;
1608         hash_objs[0].data = plain_out.data;
1609         hash_objs[1].len = gsshdr->len;
1610         hash_objs[1].data = gsshdr->data;
1611         hash_objs[2].len = plain_out.len - ke->ke_conf_size - sizeof(*khdr);
1612         hash_objs[2].data = plain_out.data + ke->ke_conf_size;
1613         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyi,
1614                                khdr, 3, hash_objs, 0, NULL, &cksum))
1615                 goto out_free;
1616
1617         LASSERT(cksum.len >= ke->ke_hash_size);
1618         if (memcmp((char *)(khdr + 1) + bodysize,
1619                    cksum.data + cksum.len - ke->ke_hash_size,
1620                    ke->ke_hash_size)) {
1621                 CERROR("checksum mismatch\n");
1622                 goto out_free;
1623         }
1624
1625         msg->len =  bodysize - ke->ke_conf_size - sizeof(*khdr);
1626         memcpy(msg->data, tmpbuf + ke->ke_conf_size, msg->len);
1627
1628         major = GSS_S_COMPLETE;
1629 out_free:
1630         OBD_FREE_LARGE(tmpbuf, bodysize);
1631         rawobj_free(&cksum);
1632         return major;
1633 }
1634
1635 static
1636 __u32 gss_unwrap_bulk_kerberos(struct gss_ctx *gctx,
1637                                struct ptlrpc_bulk_desc *desc,
1638                                rawobj_t *token, int adj_nob)
1639 {
1640         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
1641         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
1642         struct krb5_header  *khdr;
1643         int                  blocksize;
1644         rawobj_t             cksum = RAWOBJ_EMPTY;
1645         rawobj_t             cipher, plain;
1646         rawobj_t             data_desc[1];
1647         int                  rc;
1648         __u32                major;
1649
1650         LASSERT(ptlrpc_is_bulk_desc_kiov(desc->bd_type));
1651         LASSERT(ke);
1652
1653         if (token->len < sizeof(*khdr)) {
1654                 CERROR("short signature: %u\n", token->len);
1655                 return GSS_S_DEFECTIVE_TOKEN;
1656         }
1657
1658         khdr = (struct krb5_header *) token->data;
1659
1660         major = verify_krb5_header(kctx, khdr, 1);
1661         if (major != GSS_S_COMPLETE) {
1662                 CERROR("bad krb5 header\n");
1663                 return major;
1664         }
1665
1666         /* block size */
1667         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1668                 LASSERT(kctx->kc_keye.kb_tfm == NULL);
1669                 blocksize = 1;
1670                 LBUG();
1671         } else {
1672                 LASSERT(kctx->kc_keye.kb_tfm);
1673                 blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
1674         }
1675         LASSERT(sizeof(*khdr) >= blocksize && sizeof(*khdr) % blocksize == 0);
1676
1677         /*
1678          * token format is expected as:
1679          * -----------------------------------------------
1680          * | krb5 header | head/tail cipher text | cksum |
1681          * -----------------------------------------------
1682          */
1683         if (token->len < sizeof(*khdr) + blocksize + sizeof(*khdr) +
1684                          ke->ke_hash_size) {
1685                 CERROR("short token size: %u\n", token->len);
1686                 return GSS_S_DEFECTIVE_TOKEN;
1687         }
1688
1689         cipher.data = (__u8 *) (khdr + 1);
1690         cipher.len = blocksize + sizeof(*khdr);
1691         plain.data = cipher.data;
1692         plain.len = cipher.len;
1693
1694         rc = krb5_decrypt_bulk(kctx->kc_keye.kb_tfm, khdr,
1695                                desc, &cipher, &plain, adj_nob);
1696         if (rc)
1697                 return GSS_S_DEFECTIVE_TOKEN;
1698
1699         /*
1700          * verify checksum, compose clear text as layout:
1701          * ------------------------------------------
1702          * | confounder | clear pages | krb5 header |
1703          * ------------------------------------------
1704          */
1705         data_desc[0].data = plain.data;
1706         data_desc[0].len = blocksize;
1707
1708         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyi,
1709                                khdr, 1, data_desc,
1710                                desc->bd_iov_count,
1711                                GET_KIOV(desc),
1712                                &cksum))
1713                 return GSS_S_FAILURE;
1714         LASSERT(cksum.len >= ke->ke_hash_size);
1715
1716         if (memcmp(plain.data + blocksize + sizeof(*khdr),
1717                    cksum.data + cksum.len - ke->ke_hash_size,
1718                    ke->ke_hash_size)) {
1719                 CERROR("checksum mismatch\n");
1720                 rawobj_free(&cksum);
1721                 return GSS_S_BAD_SIG;
1722         }
1723
1724         rawobj_free(&cksum);
1725         return GSS_S_COMPLETE;
1726 }
1727
1728 int gss_display_kerberos(struct gss_ctx        *ctx,
1729                          char                  *buf,
1730                          int                    bufsize)
1731 {
1732         struct krb5_ctx    *kctx = ctx->internal_ctx_id;
1733         int                 written;
1734
1735         written = snprintf(buf, bufsize, "krb5 (%s)",
1736                            enctype2str(kctx->kc_enctype));
1737         return written;
1738 }
1739
1740 static struct gss_api_ops gss_kerberos_ops = {
1741         .gss_import_sec_context     = gss_import_sec_context_kerberos,
1742         .gss_copy_reverse_context   = gss_copy_reverse_context_kerberos,
1743         .gss_inquire_context        = gss_inquire_context_kerberos,
1744         .gss_get_mic                = gss_get_mic_kerberos,
1745         .gss_verify_mic             = gss_verify_mic_kerberos,
1746         .gss_wrap                   = gss_wrap_kerberos,
1747         .gss_unwrap                 = gss_unwrap_kerberos,
1748         .gss_prep_bulk              = gss_prep_bulk_kerberos,
1749         .gss_wrap_bulk              = gss_wrap_bulk_kerberos,
1750         .gss_unwrap_bulk            = gss_unwrap_bulk_kerberos,
1751         .gss_delete_sec_context     = gss_delete_sec_context_kerberos,
1752         .gss_display                = gss_display_kerberos,
1753 };
1754
1755 static struct subflavor_desc gss_kerberos_sfs[] = {
1756         {
1757                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5N,
1758                 .sf_qop         = 0,
1759                 .sf_service     = SPTLRPC_SVC_NULL,
1760                 .sf_name        = "krb5n"
1761         },
1762         {
1763                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5A,
1764                 .sf_qop         = 0,
1765                 .sf_service     = SPTLRPC_SVC_AUTH,
1766                 .sf_name        = "krb5a"
1767         },
1768         {
1769                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5I,
1770                 .sf_qop         = 0,
1771                 .sf_service     = SPTLRPC_SVC_INTG,
1772                 .sf_name        = "krb5i"
1773         },
1774         {
1775                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5P,
1776                 .sf_qop         = 0,
1777                 .sf_service     = SPTLRPC_SVC_PRIV,
1778                 .sf_name        = "krb5p"
1779         },
1780 };
1781
1782 /*
1783  * currently we leave module owner NULL
1784  */
1785 static struct gss_api_mech gss_kerberos_mech = {
1786         .gm_owner       = NULL, /*THIS_MODULE, */
1787         .gm_name        = "krb5",
1788         .gm_oid         = (rawobj_t)
1789                                 {9, "\052\206\110\206\367\022\001\002\002"},
1790         .gm_ops         = &gss_kerberos_ops,
1791         .gm_sf_num      = 4,
1792         .gm_sfs         = gss_kerberos_sfs,
1793 };
1794
1795 int __init init_kerberos_module(void)
1796 {
1797         int status;
1798
1799         spin_lock_init(&krb5_seq_lock);
1800
1801         status = lgss_mech_register(&gss_kerberos_mech);
1802         if (status)
1803                 CERROR("Failed to register kerberos gss mechanism!\n");
1804         return status;
1805 }
1806
1807 void cleanup_kerberos_module(void)
1808 {
1809         lgss_mech_unregister(&gss_kerberos_mech);
1810 }