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