Whamcloud - gitweb
LU-14462 gss: fix support for namespace in lgss_keyring
[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) 2012, 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 #ifdef HAVE_DES3_SUPPORT
201 extern void *krb5int_enc_des3;
202 #endif
203 extern void *krb5int_enc_aes128;
204 extern void *krb5int_enc_aes256;
205
206 static void
207 key_lucid_to_krb5(const gss_krb5_lucid_key_t *lin, krb5_keyblock *kout)
208 {
209         memset(kout, 0, sizeof(*kout));
210 #ifdef HAVE_KRB5
211         kout->enctype = lin->type;
212         kout->length = lin->length;
213         kout->contents = lin->data;
214 #else
215         kout->keytype = lin->type;
216         kout->keyvalue.length = lin->length;
217         kout->keyvalue.data = lin->data;
218 #endif
219 }
220
221 static int
222 key_krb5_to_lucid(const krb5_keyblock *kin, gss_krb5_lucid_key_t *lout)
223 {
224         memset(lout, 0, sizeof(*lout));
225
226 #ifdef HAVE_KRB5
227         lout->data = malloc(kin->length);
228         if (lout->data == NULL)
229                 return KRB5_CC_NOMEM;
230
231         lout->type = kin->enctype;
232         lout->length = kin->length;
233         memcpy(lout->data, kin->contents, kin->length);
234 #else
235         lout->data = malloc(kin->keyvalue.length);
236         if (lout->data == NULL)
237                 return KRB5_CC_NOMEM;
238
239         lout->type = kin->keytype;
240         lout->length = kin->keyvalue.length;
241         memcpy(lout->data, kin->keyvalue.data, kin->keyvalue.length);
242 #endif
243
244         return 0;
245 }
246
247 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
248 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
249 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
250 /* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
251 /*
252  * Function to derive a new key from a given key and given constant data.
253  */
254 static krb5_error_code
255 derive_key_lucid(const gss_krb5_lucid_key_t *in, gss_krb5_lucid_key_t *out,
256                  int usage, char extra)
257 {
258         krb5_error_code code;
259         unsigned char constant_data[K5CLENGTH];
260         krb5_data datain;
261         int keylength __attribute__ ((unused));
262 #ifdef HAVE_KRB5
263         void *enc;
264 #endif
265         krb5_keyblock kin;  /* must send krb5_keyblock, not lucid! */
266 #if defined(HAVE_HEIMDAL) || HAVE_KRB5INT_DERIVE_KEY
267         krb5_context kcontext;
268         krb5_keyblock *outkey;
269 #else
270         krb5_keyblock kout;
271 #endif
272 #if HAVE_KRB5INT_DERIVE_KEY
273         krb5_key key_in, key_out;
274 #endif
275
276         /*
277          * XXX Hack alert.  We don't have "legal" access to these
278          * values and structures located in libk5crypto
279          */
280         switch (in->type) {
281 #ifdef HAVE_DES3_SUPPORT
282         case ENCTYPE_DES3_CBC_SHA1:
283 #ifdef HAVE_KRB5
284         case ENCTYPE_DES3_CBC_RAW:
285 #endif
286                 keylength = 24;
287 #ifdef HAVE_KRB5
288                 enc = &krb5int_enc_des3;
289 #endif
290                 break;
291 #endif
292         case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
293                 keylength = 16;
294 #ifdef HAVE_KRB5
295                 enc = &krb5int_enc_aes128;
296 #endif
297                 break;
298         case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
299                 keylength = 32;
300 #ifdef HAVE_KRB5
301                 enc = &krb5int_enc_aes256;
302 #endif
303                 break;
304         default:
305                 code = KRB5_BAD_ENCTYPE;
306                 goto out;
307         }
308
309         /* Convert to correct format for call to krb5_derive_key */
310         key_lucid_to_krb5(in, &kin);
311
312         datain.data = (char *) constant_data;
313         datain.length = K5CLENGTH;
314
315         ((char *)(datain.data))[0] = (usage>>24)&0xff;
316         ((char *)(datain.data))[1] = (usage>>16)&0xff;
317         ((char *)(datain.data))[2] = (usage>>8)&0xff;
318         ((char *)(datain.data))[3] = usage&0xff;
319
320         ((char *)(datain.data))[4] = (char) extra;
321
322         /* Step 1: Init context */
323         /* Heimdal and newer MIT Kerberos require kcontext */
324 #if defined(HAVE_KRB5INT_DERIVE_KEY) || defined(HAVE_HEIMDAL)
325         code = krb5_init_context(&kcontext);
326         if (code)
327                 goto out;
328 #endif
329
330         /* Step 2: Get the derived key */
331 #ifdef HAVE_KRB5
332 #if HAVE_KRB5INT_DERIVE_KEY
333         code = krb5_k_create_key(kcontext, &kin, &key_in);
334         if (code)
335                 goto out;
336
337         code = ll_krb5int_derive_key(enc, key_in, &key_out, &datain,
338                                      DERIVE_RFC3961);
339
340         krb5_k_free_key(kcontext, key_in);
341         if (code == 0) {
342                 krb5_k_key_keyblock(kcontext, key_out, &outkey);
343                 krb5_k_free_key(kcontext, key_out);
344         }
345 #else  /* !HAVE_KRB5INT_DERIVE_KEY */
346         out->length = keylength;
347         out->type = in->type;
348
349         key_lucid_to_krb5(out, &kout);
350
351         code = krb5_derive_key(enc, &kin, &kout, &datain);
352 #endif  /* HAVE_KRB5INT_DERIVE_KEY */
353 #else   /* !defined(HAVE_KRB5) */
354         code = krb5_derive_key(kcontext, &kin, in->type, constant_data, K5CLENGTH, &outkey);
355 #endif  /* defined(HAVE_KRB5) */
356
357         if (code)
358                 goto out;
359
360         /* Step 3: Copy the key to out */
361 #if defined(HAVE_KRB5INT_DERIVE_KEY) || defined(HAVE_HEIMDAL)
362         code = key_krb5_to_lucid(outkey, out);
363         krb5_free_keyblock(kcontext, outkey);
364 #else   /* !defined(HAVE_KRB5) */
365         code = key_krb5_to_lucid(&kout, out);
366 #endif  /* defined(HAVE_KRB5) */
367
368         /* Step 4: Free the context */
369 #if defined(HAVE_KRB5INT_DERIVE_KEY) || defined(HAVE_HEIMDAL)
370         krb5_free_context(kcontext);
371 #endif
372
373   out:
374         if (code)
375                 printerr(0, "ERROR: %s: returning error %d (%s)\n",
376                          __FUNCTION__, code, error_message(code));
377         return (code);
378 }
379
380
381 /*
382  * Prepare a new-style buffer, as defined in rfc4121 (a.k.a. cfx),
383  * to send to the kernel for newer encryption types -- or for DES3.
384  *
385  * The new format is:
386  *
387  *      u32 initiate;                   ( whether we are the initiator or not )
388  *      s32 endtime;
389  *      u32 flags;
390  *      #define KRB5_CTX_FLAG_INITIATOR         0x00000001
391  *      #define KRB5_CTX_FLAG_CFX               0x00000002
392  *      #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
393  *      u64 seq_send;
394  *      u32  enctype;                   ( encrption type of keys )
395  *      u32  size_of_each_key;          ( size of each key in bytes )
396  *      u32  number_of_keys;            ( N -- should always be 3 for now )
397  *      keydata-1;                      ( Ke )
398  *      keydata-2;                      ( Ki )
399  *      keydata-3;                      ( Kc )
400  *
401  */
402 static int
403 prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx,
404                             gss_buffer_desc *buf)
405 {
406         static int constant_two = 2;
407         char *p, *end;
408         uint32_t v2_flags = 0;
409         gss_krb5_lucid_key_t enc_key;
410         gss_krb5_lucid_key_t derived_key;
411         gss_buffer_desc fakeoid;
412         uint32_t enctype;
413         uint32_t keysize;
414         uint32_t numkeys;
415
416         memset(&enc_key, 0, sizeof(enc_key));
417         memset(&fakeoid, 0, sizeof(fakeoid));
418
419         if (!(buf->value = calloc(1, MAX_CTX_LEN)))
420                 goto out_err;
421         p = buf->value;
422         end = buf->value + MAX_CTX_LEN;
423
424         /* Version 2 */
425         if (WRITE_BYTES(&p, end, constant_two)) goto out_err;
426         if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
427
428         if (lctx->initiate)
429                 v2_flags |= KRB5_CTX_FLAG_INITIATOR;
430         if (lctx->protocol != 0)
431                 v2_flags |= KRB5_CTX_FLAG_CFX;
432         if (lctx->protocol != 0 && lctx->cfx_kd.have_acceptor_subkey == 1)
433                 v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
434
435         if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
436
437         if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err;
438
439         /* Protocol 0 here implies DES3 or RC4 */
440         printerr(3, "protocol %d\n", lctx->protocol);
441         if (lctx->protocol == 0) {
442                 enctype = lctx->rfc1964_kd.ctx_key.type;
443 #ifdef HAVE_HEIMDAL
444                 /*
445                  * The kernel gss code expects ENCTYPE_DES3_CBC_RAW (6) for
446                  * 3des keys, but Heimdal key has ENCTYPE_DES3_CBC_SHA1 (16).
447                  * Force the Heimdal enctype to 6.
448                  */
449                 if (enctype == ENCTYPE_DES3_CBC_SHA1) {
450                         printerr(2, "%s: overriding heimdal keytype (%d => %d)\n",
451                                  __FUNCTION__, enctype, 6);
452
453                         enctype = 6;
454                 }
455 #endif
456                 keysize = lctx->rfc1964_kd.ctx_key.length;
457                 numkeys = 3;    /* XXX is always gonna be three? */
458         } else {
459                 if (lctx->cfx_kd.have_acceptor_subkey) {
460                         enctype = lctx->cfx_kd.acceptor_subkey.type;
461                         keysize = lctx->cfx_kd.acceptor_subkey.length;
462                 } else {
463                         enctype = lctx->cfx_kd.ctx_key.type;
464                         keysize = lctx->cfx_kd.ctx_key.length;
465                 }
466                 numkeys = 3;
467         }
468         printerr(3, "serializing %d keys with enctype %d and size %d\n",
469                  numkeys, enctype, keysize);
470         if (WRITE_BYTES(&p, end, enctype)) goto out_err;
471         if (WRITE_BYTES(&p, end, keysize)) goto out_err;
472         if (WRITE_BYTES(&p, end, numkeys)) goto out_err;
473
474         if (lctx->protocol == 0) {
475                 /* derive and send down: Ke, Ki, and Kc */
476                 /* Ke */
477                 if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
478                                 lctx->rfc1964_kd.ctx_key.length))
479                         goto out_err;
480
481                 /* Ki */
482                 if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
483                                 lctx->rfc1964_kd.ctx_key.length))
484                         goto out_err;
485
486                 /* Kc */
487                 /*
488                  * RC4 is special, it dosen't need key derivation. Actually
489                  * the Ke is based on plain text. Here we just let all three
490                  * key identical, kernel will handle everything. --ericm
491                  */
492                 if (lctx->rfc1964_kd.ctx_key.type == ENCTYPE_ARCFOUR_HMAC) {
493                         if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
494                                         lctx->rfc1964_kd.ctx_key.length))
495                                 goto out_err;
496                 } else {
497                         if (derive_key_lucid(&lctx->rfc1964_kd.ctx_key,
498                                         &derived_key,
499                                         KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM))
500                                 goto out_err;
501                         if (write_bytes(&p, end, derived_key.data,
502                                         derived_key.length))
503                                 goto out_err;
504                         free(derived_key.data);
505                 }
506         } else {
507                 gss_krb5_lucid_key_t *keyptr;
508                 uint32_t sign_usage, seal_usage;
509
510                 if (lctx->cfx_kd.have_acceptor_subkey)
511                         keyptr = &lctx->cfx_kd.acceptor_subkey;
512                 else
513                         keyptr = &lctx->cfx_kd.ctx_key;
514
515                 /* FIXME
516                  * These are from rfc4142, but I don't understand:
517                  * if we supply different 'usage' value for client &
518                  * server, then the peers will have different derived
519                  * keys. How could this work?
520                  *
521                  * Here we simply use old SIGN/SEAL values until we
522                  * find the answer.  --ericm
523                  * FIXME
524                  */
525                 sign_usage = KG_USAGE_SIGN;
526                 seal_usage = KG_USAGE_SEAL;
527
528                 /* derive and send down: Ke, Ki, and Kc */
529
530                 /* Ke */
531                 if (derive_key_lucid(keyptr, &derived_key,
532                                seal_usage, KEY_USAGE_SEED_ENCRYPTION))
533                         goto out_err;
534                 if (write_bytes(&p, end, derived_key.data,
535                                 derived_key.length))
536                         goto out_err;
537                 free(derived_key.data);
538
539                 /* Ki */
540                 if (derive_key_lucid(keyptr, &derived_key,
541                                seal_usage, KEY_USAGE_SEED_INTEGRITY))
542                         goto out_err;
543                 if (write_bytes(&p, end, derived_key.data,
544                                 derived_key.length))
545                         goto out_err;
546                 free(derived_key.data);
547
548                 /* Kc */
549                 if (derive_key_lucid(keyptr, &derived_key,
550                                sign_usage, KEY_USAGE_SEED_CHECKSUM))
551                         goto out_err;
552                 if (write_bytes(&p, end, derived_key.data,
553                                 derived_key.length))
554                         goto out_err;
555                 free(derived_key.data);
556         }
557
558         buf->length = p - (char *)buf->value;
559         return 0;
560
561 out_err:
562         printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n",
563                  __FUNCTION__);
564         if (buf->value) {
565                 free(buf->value);
566                 buf->value = NULL;
567         }
568         buf->length = 0;
569         if (enc_key.data) {
570                 free(enc_key.data);
571                 enc_key.data = NULL;
572         }
573         return -1;
574 }
575 int
576 serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf)
577 {
578         OM_uint32 maj_stat, min_stat;
579         void *return_ctx = 0;
580         OM_uint32 vers;
581         gss_krb5_lucid_context_v1_t *lctx = 0;
582         int retcode = 0;
583
584         printerr(3, "lucid version!\n");
585         maj_stat = gss_krb5_export_lucid_sec_context(&min_stat, &ctx,
586                                                 1, &return_ctx);
587         if (maj_stat != GSS_S_COMPLETE) {
588                 pgsserr("gss_krb5_export_lucid_sec_context",
589                         maj_stat, min_stat, &krb5oid);
590                 goto out_err;
591         }
592
593         /* Check the version returned, we only support v1 right now */
594         vers = ((gss_krb5_lucid_context_version_t *)return_ctx)->version;
595         switch (vers) {
596         case 1:
597                 lctx = (gss_krb5_lucid_context_v1_t *) return_ctx;
598                 break;
599         default:
600                 printerr(0, "ERROR: unsupported lucid sec context version %d\n",
601                         vers);
602                 goto out_err;
603                 break;
604         }
605
606         /*
607          * Now lctx points to a lucid context that we can send down to kernel
608          *
609          * Note: we send down different information to the kernel depending
610          * on the protocol version and the enctyption type.
611          * For protocol version 0 with all enctypes besides DES3, we use
612          * the original format.  For protocol version != 0 or DES3, we
613          * send down the new style information.
614          */
615
616         if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4)
617                 retcode = prepare_krb5_rfc1964_buffer(lctx, buf);
618         else
619                 retcode = prepare_krb5_rfc4121_buffer(lctx, buf);
620
621         maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, return_ctx);
622         if (maj_stat != GSS_S_COMPLETE) {
623                 pgsserr("gss_krb5_export_lucid_sec_context",
624                         maj_stat, min_stat, &krb5oid);
625                 printerr(0, "WARN: failed to free lucid sec context\n");
626         }
627
628         if (retcode) {
629                 printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n",
630                          __FUNCTION__, retcode);
631                 goto out_err;
632         }
633
634         return 0;
635
636 out_err:
637         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
638         return -1;
639 }
640
641
642
643 #endif /* HAVE_LUCID_CONTEXT_SUPPORT */