Whamcloud - gitweb
LU-8058 utils: Remove old commented out code
[fs/lustre-release.git] / lustre / utils / gss / context_lucid.c
1 /*
2  * COPYRIGHT (c) 2006 The Regents of the University of Michigan
3  * ALL RIGHTS RESERVED
4  *
5  * Copyright (c) 2014, Intel Corporation.
6  *
7  * Permission is granted to use, copy, create derivative works
8  * and redistribute this software and such derivative works
9  * for any purpose, so long as the name of The University of
10  * Michigan is not used in any advertising or publicity
11  * pertaining to the use of distribution of this software
12  * without specific, written prior authorization.  If the
13  * above copyright notice or any other identification of the
14  * University of Michigan is included in any copy of any
15  * portion of this software, then the disclaimer below must
16  * also be included.
17  *
18  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
19  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
20  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
21  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
22  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
24  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
25  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
26  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
27  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
28  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGES.
30  */
31
32 #include "config.h"
33
34 #ifdef HAVE_LUCID_CONTEXT_SUPPORT
35
36 /*
37  * Newer versions of MIT and Heimdal have lucid context support.
38  * We can use common code if it is supported.
39  */
40
41 #include <stdio.h>
42 #include <syslog.h>
43 #include <string.h>
44 #include <errno.h>
45 #include <stdint.h>
46 #include <krb5.h>
47 #include <gssapi/gssapi.h>
48 #ifndef OM_uint64
49 typedef uint64_t OM_uint64;
50 #endif
51 #include <gssapi/gssapi_krb5.h>
52
53 #ifdef _NEW_BUILD_
54 # include "lgss_utils.h"
55 #else
56 # include "gss_util.h"
57 # include "gss_oids.h"
58 # include "err_util.h"
59 #endif
60 #include "write_bytes.h"
61 #include "context.h"
62
63
64 static int
65 write_lucid_keyblock(char **p, char *end, gss_krb5_lucid_key_t *key)
66 {
67         gss_buffer_desc tmp;
68
69         if (WRITE_BYTES(p, end, key->type)) return -1;
70         tmp.length = key->length;
71         tmp.value = key->data;
72         if (write_buffer(p, end, &tmp)) return -1;
73         return 0;
74 }
75
76 static int
77 prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx,
78         gss_buffer_desc *buf)
79 {
80         char *p, *end;
81         static int constant_zero = 0;
82         unsigned char fakeseed[16] = { 0 };
83         uint32_t word_send_seq;
84         gss_krb5_lucid_key_t enc_key;
85         int i;
86         char *skd, *dkd;
87
88         /*
89          * The new Kerberos interface to get the gss context
90          * does not include the seed or seed_init fields
91          * because we never really use them.  But for now,
92          * send down a fake buffer so we can use the same
93          * interface to the kernel.
94          */
95         memset(&enc_key, 0, sizeof(enc_key));
96
97         if (!(buf->value = calloc(1, MAX_CTX_LEN)))
98                 goto out_err;
99         p = buf->value;
100         end = buf->value + MAX_CTX_LEN;
101
102         if (WRITE_BYTES(&p, end, lctx->initiate)) goto out_err;
103
104         /* seed_init and seed not used by kernel anyway */
105         if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
106         if (write_bytes(&p, end, &fakeseed, 16)) goto out_err;
107
108         if (WRITE_BYTES(&p, end, lctx->rfc1964_kd.sign_alg)) goto out_err;
109         if (WRITE_BYTES(&p, end, lctx->rfc1964_kd.seal_alg)) goto out_err;
110         if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
111         word_send_seq = lctx->send_seq; /* XXX send_seq is 64-bit */
112         if (WRITE_BYTES(&p, end, word_send_seq)) goto out_err;
113         if (write_oid(&p, end, &krb5oid)) goto out_err;
114
115 #ifdef HAVE_HEIMDAL
116         /*
117          * The kernel gss code expects des-cbc-raw for all flavors of des.
118          * The keytype from MIT has this type, but Heimdal does not.
119          * Force the Heimdal keytype to 4 (des-cbc-raw).
120          * Note that the rfc1964 version only supports DES enctypes.
121          */
122         if (lctx->rfc1964_kd.ctx_key.type != 4) {
123                 printerr(2, "%s: overriding heimdal keytype (%d => %d)\n",
124                          __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, 4);
125                 lctx->rfc1964_kd.ctx_key.type = 4;
126         }
127 #endif
128         printerr(2, "%s: serializing keys with enctype %d and length %d\n",
129                  __FUNCTION__, lctx->rfc1964_kd.ctx_key.type,
130                  lctx->rfc1964_kd.ctx_key.length);
131
132         /* derive the encryption key and copy it into buffer */
133         enc_key.type = lctx->rfc1964_kd.ctx_key.type;
134         enc_key.length = lctx->rfc1964_kd.ctx_key.length;
135         if ((enc_key.data = calloc(1, enc_key.length)) == NULL)
136                 goto out_err;
137         skd = (char *) lctx->rfc1964_kd.ctx_key.data;
138         dkd = (char *) enc_key.data;
139         for (i = 0; i < enc_key.length; i++)
140                 dkd[i] = skd[i] ^ 0xf0;
141         if (write_lucid_keyblock(&p, end, &enc_key))
142                 goto out_err;
143         if (write_lucid_keyblock(&p, end, &lctx->rfc1964_kd.ctx_key))
144                 goto out_err;
145         free(enc_key.data);
146
147         buf->length = p - (char *)buf->value;
148         return 0;
149 out_err:
150         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
151         if (buf->value) {
152                 free(buf->value);
153                 buf->value = NULL;
154         }
155         buf->length = 0;
156         if (enc_key.data) free(enc_key.data);
157         return -1;
158 }
159
160 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
161 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
162
163 /* for 3DES */
164 #define KG_USAGE_SEAL 22
165 #define KG_USAGE_SIGN 23
166 #define KG_USAGE_SEQ  24
167
168 /* for rfc???? */
169 #define KG_USAGE_ACCEPTOR_SEAL  22
170 #define KG_USAGE_ACCEPTOR_SIGN  23
171 #define KG_USAGE_INITIATOR_SEAL 24
172 #define KG_USAGE_INITIATOR_SIGN 25
173
174 /* Lifted from mit src/lib/gssapi/krb5/gssapiP_krb5.h */
175 enum seal_alg {
176   SEAL_ALG_NONE            = 0xffff,
177   SEAL_ALG_DES             = 0x0000,
178   SEAL_ALG_1               = 0x0001, /* not published */
179   SEAL_ALG_MICROSOFT_RC4   = 0x0010, /* microsoft w2k;  */
180   SEAL_ALG_DES3KD          = 0x0002
181 };
182
183 #define KEY_USAGE_SEED_ENCRYPTION       0xAA
184 #define KEY_USAGE_SEED_INTEGRITY        0x55
185 #define KEY_USAGE_SEED_CHECKSUM         0x99
186 #define K5CLENGTH 5
187
188 /* Flags for version 2 context flags */
189 #define KRB5_CTX_FLAG_INITIATOR         0x00000001
190 #define KRB5_CTX_FLAG_CFX               0x00000002
191 #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
192
193 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
194 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
195 /*
196  * We don't have "legal" access to these MIT-only
197  * structures located in libk5crypto
198  */
199 extern void *krb5int_enc_arcfour;
200 extern void *krb5int_enc_des3;
201 extern void *krb5int_enc_aes128;
202 extern void *krb5int_enc_aes256;
203
204 static void
205 key_lucid_to_krb5(const gss_krb5_lucid_key_t *lin, krb5_keyblock *kout)
206 {
207         memset(kout, 0, sizeof(*kout));
208 #ifdef HAVE_KRB5
209         kout->enctype = lin->type;
210         kout->length = lin->length;
211         kout->contents = lin->data;
212 #else
213         kout->keytype = lin->type;
214         kout->keyvalue.length = lin->length;
215         kout->keyvalue.data = lin->data;
216 #endif
217 }
218
219 static int
220 key_krb5_to_lucid(const krb5_keyblock *kin, gss_krb5_lucid_key_t *lout)
221 {
222         memset(lout, 0, sizeof(*lout));
223
224 #ifdef HAVE_KRB5
225         lout->data = malloc(kin->length);
226         if (lout->data == NULL)
227                 return KRB5_CC_NOMEM;
228
229         lout->type = kin->enctype;
230         lout->length = kin->length;
231         memcpy(lout->data, kin->contents, kin->length);
232 #else
233         lout->data = malloc(kin->keyvalue.length);
234         if (lout->data == NULL)
235                 return KRB5_CC_NOMEM;
236
237         lout->type = kin->keytype;
238         lout->length = kin->keyvalue.length;
239         memcpy(lout->data, kin->keyvalue.data, kin->keyvalue.length);
240 #endif
241
242         return 0;
243 }
244
245 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
246 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
247 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
248 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
249 /*
250  * Function to derive a new key from a given key and given constant data.
251  */
252 static krb5_error_code
253 derive_key_lucid(const gss_krb5_lucid_key_t *in, gss_krb5_lucid_key_t *out,
254                  int usage, char extra)
255 {
256         krb5_error_code code;
257         unsigned char constant_data[K5CLENGTH];
258         krb5_data datain;
259         int keylength __attribute__ ((unused));
260 #ifdef HAVE_KRB5
261         void *enc;
262 #endif
263         krb5_keyblock kin;  /* must send krb5_keyblock, not lucid! */
264 #if defined(HAVE_HEIMDAL) || HAVE_KRB5INT_DERIVE_KEY
265         krb5_context kcontext;
266         krb5_keyblock *outkey;
267 #else
268         krb5_keyblock kout;
269 #endif
270 #if HAVE_KRB5INT_DERIVE_KEY
271         krb5_key key_in, key_out;
272 #endif
273
274         /*
275          * XXX Hack alert.  We don't have "legal" access to these
276          * values and structures located in libk5crypto
277          */
278         switch (in->type) {
279         case ENCTYPE_DES3_CBC_SHA1:
280 #ifdef HAVE_KRB5
281         case ENCTYPE_DES3_CBC_RAW:
282 #endif
283                 keylength = 24;
284 #ifdef HAVE_KRB5
285                 enc = &krb5int_enc_des3;
286 #endif
287                 break;
288         case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
289                 keylength = 16;
290 #ifdef HAVE_KRB5
291                 enc = &krb5int_enc_aes128;
292 #endif
293                 break;
294         case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
295                 keylength = 32;
296 #ifdef HAVE_KRB5
297                 enc = &krb5int_enc_aes256;
298 #endif
299                 break;
300         default:
301                 code = KRB5_BAD_ENCTYPE;
302                 goto out;
303         }
304
305         /* Convert to correct format for call to krb5_derive_key */
306         key_lucid_to_krb5(in, &kin);
307
308         datain.data = (char *) constant_data;
309         datain.length = K5CLENGTH;
310
311         ((char *)(datain.data))[0] = (usage>>24)&0xff;
312         ((char *)(datain.data))[1] = (usage>>16)&0xff;
313         ((char *)(datain.data))[2] = (usage>>8)&0xff;
314         ((char *)(datain.data))[3] = usage&0xff;
315
316         ((char *)(datain.data))[4] = (char) extra;
317
318         /* Step 1: Init context */
319         /* Heimdal and newer MIT Kerberos require kcontext */
320 #if defined(HAVE_KRB5INT_DERIVE_KEY) || defined(HAVE_HEIMDAL)
321         code = krb5_init_context(&kcontext);
322         if (code)
323                 goto out;
324 #endif
325
326         /* Step 2: Get the derived key */
327 #ifdef HAVE_KRB5
328 #if HAVE_KRB5INT_DERIVE_KEY
329         code = krb5_k_create_key(kcontext, &kin, &key_in);
330         if (code)
331                 goto out;
332
333         code = krb5int_derive_key(enc, key_in, &key_out, &datain,
334                                   DERIVE_RFC3961);
335
336         krb5_k_free_key(kcontext, key_in);
337         if (code == 0) {
338                 krb5_k_key_keyblock(kcontext, key_out, &outkey);
339                 krb5_k_free_key(kcontext, key_out);
340         }
341 #else  /* !HAVE_KRB5INT_DERIVE_KEY */
342         out->length = keylength;
343         out->type = in->type;
344
345         key_lucid_to_krb5(out, &kout);
346
347         code = krb5_derive_key(enc, &kin, &kout, &datain);
348 #endif  /* HAVE_KRB5INT_DERIVE_KEY */
349 #else   /* !defined(HAVE_KRB5) */
350         code = krb5_derive_key(kcontext, &kin, in->type, constant_data, K5CLENGTH, &outkey);
351 #endif  /* defined(HAVE_KRB5) */
352
353         if (code)
354                 goto out;
355
356         /* Step 3: Copy the key to out */
357 #if defined(HAVE_KRB5INT_DERIVE_KEY) || defined(HAVE_HEIMDAL)
358         code = key_krb5_to_lucid(outkey, out);
359         krb5_free_keyblock(kcontext, outkey);
360 #else   /* !defined(HAVE_KRB5) */
361         code = key_krb5_to_lucid(&kout, out);
362 #endif  /* defined(HAVE_KRB5) */
363
364         /* Step 4: Free the context */
365 #if defined(HAVE_KRB5INT_DERIVE_KEY) || defined(HAVE_HEIMDAL)
366         krb5_free_context(kcontext);
367 #endif
368
369   out:
370         if (code)
371                 printerr(0, "ERROR: %s: returning error %d (%s)\n",
372                          __FUNCTION__, code, error_message(code));
373         return (code);
374 }
375
376
377 /*
378  * Prepare a new-style buffer, as defined in rfc4121 (a.k.a. cfx),
379  * to send to the kernel for newer encryption types -- or for DES3.
380  *
381  * The new format is:
382  *
383  *      u32 initiate;                   ( whether we are the initiator or not )
384  *      s32 endtime;
385  *      u32 flags;
386  *      #define KRB5_CTX_FLAG_INITIATOR         0x00000001
387  *      #define KRB5_CTX_FLAG_CFX               0x00000002
388  *      #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
389  *      u64 seq_send;
390  *      u32  enctype;                   ( encrption type of keys )
391  *      u32  size_of_each_key;          ( size of each key in bytes )
392  *      u32  number_of_keys;            ( N -- should always be 3 for now )
393  *      keydata-1;                      ( Ke )
394  *      keydata-2;                      ( Ki )
395  *      keydata-3;                      ( Kc )
396  *
397  */
398 static int
399 prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx,
400                             gss_buffer_desc *buf)
401 {
402         static int constant_two = 2;
403         char *p, *end;
404         uint32_t v2_flags = 0;
405         gss_krb5_lucid_key_t enc_key;
406         gss_krb5_lucid_key_t derived_key;
407         gss_buffer_desc fakeoid;
408         uint32_t enctype;
409         uint32_t keysize;
410         uint32_t numkeys;
411
412         memset(&enc_key, 0, sizeof(enc_key));
413         memset(&fakeoid, 0, sizeof(fakeoid));
414
415         if (!(buf->value = calloc(1, MAX_CTX_LEN)))
416                 goto out_err;
417         p = buf->value;
418         end = buf->value + MAX_CTX_LEN;
419
420         /* Version 2 */
421         if (WRITE_BYTES(&p, end, constant_two)) goto out_err;
422         if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
423
424         if (lctx->initiate)
425                 v2_flags |= KRB5_CTX_FLAG_INITIATOR;
426         if (lctx->protocol != 0)
427                 v2_flags |= KRB5_CTX_FLAG_CFX;
428         if (lctx->protocol != 0 && lctx->cfx_kd.have_acceptor_subkey == 1)
429                 v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
430
431         if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
432
433         if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err;
434
435         /* Protocol 0 here implies DES3 or RC4 */
436         printerr(3, "protocol %d\n", lctx->protocol);
437         if (lctx->protocol == 0) {
438                 enctype = lctx->rfc1964_kd.ctx_key.type;
439 #ifdef HAVE_HEIMDAL
440                 /*
441                  * The kernel gss code expects ENCTYPE_DES3_CBC_RAW (6) for
442                  * 3des keys, but Heimdal key has ENCTYPE_DES3_CBC_SHA1 (16).
443                  * Force the Heimdal enctype to 6.
444                  */
445                 if (enctype == ENCTYPE_DES3_CBC_SHA1) {
446                         printerr(2, "%s: overriding heimdal keytype (%d => %d)\n",
447                                  __FUNCTION__, enctype, 6);
448
449                         enctype = 6;
450                 }
451 #endif
452                 keysize = lctx->rfc1964_kd.ctx_key.length;
453                 numkeys = 3;    /* XXX is always gonna be three? */
454         } else {
455                 if (lctx->cfx_kd.have_acceptor_subkey) {
456                         enctype = lctx->cfx_kd.acceptor_subkey.type;
457                         keysize = lctx->cfx_kd.acceptor_subkey.length;
458                 } else {
459                         enctype = lctx->cfx_kd.ctx_key.type;
460                         keysize = lctx->cfx_kd.ctx_key.length;
461                 }
462                 numkeys = 3;
463         }
464         printerr(3, "serializing %d keys with enctype %d and size %d\n",
465                  numkeys, enctype, keysize);
466         if (WRITE_BYTES(&p, end, enctype)) goto out_err;
467         if (WRITE_BYTES(&p, end, keysize)) goto out_err;
468         if (WRITE_BYTES(&p, end, numkeys)) goto out_err;
469
470         if (lctx->protocol == 0) {
471                 /* derive and send down: Ke, Ki, and Kc */
472                 /* Ke */
473                 if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
474                                 lctx->rfc1964_kd.ctx_key.length))
475                         goto out_err;
476
477                 /* Ki */
478                 if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
479                                 lctx->rfc1964_kd.ctx_key.length))
480                         goto out_err;
481
482                 /* Kc */
483                 /*
484                  * RC4 is special, it dosen't need key derivation. Actually
485                  * the Ke is based on plain text. Here we just let all three
486                  * key identical, kernel will handle everything. --ericm
487                  */
488                 if (lctx->rfc1964_kd.ctx_key.type == ENCTYPE_ARCFOUR_HMAC) {
489                         if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
490                                         lctx->rfc1964_kd.ctx_key.length))
491                                 goto out_err;
492                 } else {
493                         if (derive_key_lucid(&lctx->rfc1964_kd.ctx_key,
494                                         &derived_key,
495                                         KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM))
496                                 goto out_err;
497                         if (write_bytes(&p, end, derived_key.data,
498                                         derived_key.length))
499                                 goto out_err;
500                         free(derived_key.data);
501                 }
502         } else {
503                 gss_krb5_lucid_key_t *keyptr;
504                 uint32_t sign_usage, seal_usage;
505
506                 if (lctx->cfx_kd.have_acceptor_subkey)
507                         keyptr = &lctx->cfx_kd.acceptor_subkey;
508                 else
509                         keyptr = &lctx->cfx_kd.ctx_key;
510
511                 /* FIXME
512                  * These are from rfc4142, but I don't understand:
513                  * if we supply different 'usage' value for client &
514                  * server, then the peers will have different derived
515                  * keys. How could this work?
516                  *
517                  * Here we simply use old SIGN/SEAL values until we
518                  * find the answer.  --ericm
519                  * FIXME
520                  */
521                 sign_usage = KG_USAGE_SIGN;
522                 seal_usage = KG_USAGE_SEAL;
523
524                 /* derive and send down: Ke, Ki, and Kc */
525
526                 /* Ke */
527                 if (derive_key_lucid(keyptr, &derived_key,
528                                seal_usage, KEY_USAGE_SEED_ENCRYPTION))
529                         goto out_err;
530                 if (write_bytes(&p, end, derived_key.data,
531                                 derived_key.length))
532                         goto out_err;
533                 free(derived_key.data);
534
535                 /* Ki */
536                 if (derive_key_lucid(keyptr, &derived_key,
537                                seal_usage, KEY_USAGE_SEED_INTEGRITY))
538                         goto out_err;
539                 if (write_bytes(&p, end, derived_key.data,
540                                 derived_key.length))
541                         goto out_err;
542                 free(derived_key.data);
543
544                 /* Kc */
545                 if (derive_key_lucid(keyptr, &derived_key,
546                                sign_usage, KEY_USAGE_SEED_CHECKSUM))
547                         goto out_err;
548                 if (write_bytes(&p, end, derived_key.data,
549                                 derived_key.length))
550                         goto out_err;
551                 free(derived_key.data);
552         }
553
554         buf->length = p - (char *)buf->value;
555         return 0;
556
557 out_err:
558         printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n",
559                  __FUNCTION__);
560         if (buf->value) {
561                 free(buf->value);
562                 buf->value = NULL;
563         }
564         buf->length = 0;
565         if (enc_key.data) {
566                 free(enc_key.data);
567                 enc_key.data = NULL;
568         }
569         return -1;
570 }
571 int
572 serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf)
573 {
574         OM_uint32 maj_stat, min_stat;
575         void *return_ctx = 0;
576         OM_uint32 vers;
577         gss_krb5_lucid_context_v1_t *lctx = 0;
578         int retcode = 0;
579
580         printerr(3, "lucid version!\n");
581         maj_stat = gss_krb5_export_lucid_sec_context(&min_stat, &ctx,
582                                                 1, &return_ctx);
583         if (maj_stat != GSS_S_COMPLETE) {
584                 pgsserr("gss_krb5_export_lucid_sec_context",
585                         maj_stat, min_stat, &krb5oid);
586                 goto out_err;
587         }
588
589         /* Check the version returned, we only support v1 right now */
590         vers = ((gss_krb5_lucid_context_version_t *)return_ctx)->version;
591         switch (vers) {
592         case 1:
593                 lctx = (gss_krb5_lucid_context_v1_t *) return_ctx;
594                 break;
595         default:
596                 printerr(0, "ERROR: unsupported lucid sec context version %d\n",
597                         vers);
598                 goto out_err;
599                 break;
600         }
601
602         /*
603          * Now lctx points to a lucid context that we can send down to kernel
604          *
605          * Note: we send down different information to the kernel depending
606          * on the protocol version and the enctyption type.
607          * For protocol version 0 with all enctypes besides DES3, we use
608          * the original format.  For protocol version != 0 or DES3, we
609          * send down the new style information.
610          */
611
612         if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4)
613                 retcode = prepare_krb5_rfc1964_buffer(lctx, buf);
614         else
615                 retcode = prepare_krb5_rfc4121_buffer(lctx, buf);
616
617         maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, return_ctx);
618         if (maj_stat != GSS_S_COMPLETE) {
619                 pgsserr("gss_krb5_export_lucid_sec_context",
620                         maj_stat, min_stat, &krb5oid);
621                 printerr(0, "WARN: failed to free lucid sec context\n");
622         }
623
624         if (retcode) {
625                 printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n",
626                          __FUNCTION__, retcode);
627                 goto out_err;
628         }
629
630         return 0;
631
632 out_err:
633         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
634         return -1;
635 }
636
637
638
639 #endif /* HAVE_LUCID_CONTEXT_SUPPORT */