]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/gssd/context_lucid.c
gssd: initialize fakeseed in prepare_krb5_rfc1964_buffer
[nfs-utils.git] / utils / gssd / 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 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif  /* HAVE_CONFIG_H */
34
35 #ifdef HAVE_LUCID_CONTEXT_SUPPORT
36
37 /*
38  * Newer versions of MIT and Heimdal have lucid context support.
39  * We can use common code if it is supported.
40  */
41
42 #include <stdio.h>
43 #include <syslog.h>
44 #include <string.h>
45
46 #include <gssapi/gssapi_krb5.h>
47
48 #include "gss_util.h"
49 #include "gss_oids.h"
50 #include "err_util.h"
51 #include "context.h"
52
53 #ifndef OM_uint64
54 typedef uint64_t OM_uint64;
55 #endif
56
57 static int
58 write_lucid_keyblock(char **p, char *end, gss_krb5_lucid_key_t *key)
59 {
60         gss_buffer_desc tmp;
61
62         if (WRITE_BYTES(p, end, key->type)) return -1;
63         tmp.length = key->length;
64         tmp.value = key->data;
65         if (write_buffer(p, end, &tmp)) return -1;
66         return 0;
67 }
68
69 static int
70 prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx,
71         gss_buffer_desc *buf, int32_t *endtime)
72 {
73 #define FAKESEED_SIZE 16
74         char *p, *end;
75         static int constant_zero = 0;
76         unsigned char fakeseed[FAKESEED_SIZE];
77         uint32_t word_send_seq;
78         gss_krb5_lucid_key_t enc_key;
79         int i;
80         char *skd, *dkd;
81         gss_buffer_desc fakeoid;
82
83         /*
84          * The new Kerberos interface to get the gss context
85          * does not include the seed or seed_init fields
86          * because we never really use them.  But for now,
87          * send down a fake buffer so we can use the same
88          * interface to the kernel.
89          */
90         memset(&enc_key, 0, sizeof(enc_key));
91         memset(&fakeoid, 0, sizeof(fakeoid));
92         memset(fakeseed, 0, FAKESEED_SIZE);
93
94         if (!(buf->value = calloc(1, MAX_CTX_LEN)))
95                 goto out_err;
96         p = buf->value;
97         end = buf->value + MAX_CTX_LEN;
98
99         if (WRITE_BYTES(&p, end, lctx->initiate)) goto out_err;
100
101         /* seed_init and seed not used by kernel anyway */
102         if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
103         if (write_bytes(&p, end, &fakeseed, FAKESEED_SIZE)) goto out_err;
104
105         if (WRITE_BYTES(&p, end, lctx->rfc1964_kd.sign_alg)) goto out_err;
106         if (WRITE_BYTES(&p, end, lctx->rfc1964_kd.seal_alg)) goto out_err;
107         if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
108         if (endtime)
109                 *endtime = lctx->endtime;
110         word_send_seq = lctx->send_seq; /* XXX send_seq is 64-bit */
111         if (WRITE_BYTES(&p, end, word_send_seq)) goto out_err;
112         if (write_oid(&p, end, &krb5oid)) goto out_err;
113
114 #ifdef HAVE_HEIMDAL
115         /*
116          * The kernel gss code expects des-cbc-raw for all flavors of des.
117          * The keytype from MIT has this type, but Heimdal does not.
118          * Force the Heimdal keytype to 4 (des-cbc-raw).
119          * Note that the rfc1964 version only supports DES enctypes.
120          */
121         if (lctx->rfc1964_kd.ctx_key.type != 4) {
122                 printerr(1, "prepare_krb5_rfc1964_buffer: "
123                             "overriding heimdal keytype (%d => %d)\n",
124                             lctx->rfc1964_kd.ctx_key.type, 4);
125                 lctx->rfc1964_kd.ctx_key.type = 4;
126         }
127 #endif
128         printerr(2, "prepare_krb5_rfc1964_buffer: serializing keys with "
129                  "enctype %d and length %d\n",
130                  lctx->rfc1964_kd.ctx_key.type,
131                  lctx->rfc1964_kd.ctx_key.length);
132
133         /* derive the encryption key and copy it into buffer */
134         enc_key.type = lctx->rfc1964_kd.ctx_key.type;
135         enc_key.length = lctx->rfc1964_kd.ctx_key.length;
136         if ((enc_key.data = calloc(1, enc_key.length)) == NULL)
137                 goto out_err;
138         skd = (char *) lctx->rfc1964_kd.ctx_key.data;
139         dkd = (char *) enc_key.data;
140         for (i = 0; i < enc_key.length; i++)
141                 dkd[i] = skd[i] ^ 0xf0;
142         if (write_lucid_keyblock(&p, end, &enc_key)) {
143                 free(enc_key.data);
144                 goto out_err;
145         }
146         free(enc_key.data);
147
148         if (write_lucid_keyblock(&p, end, &lctx->rfc1964_kd.ctx_key))
149                 goto out_err;
150
151         buf->length = p - (char *)buf->value;
152         return 0;
153 out_err:
154         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
155         if (buf->value) free(buf->value);
156         buf->length = 0;
157         if (enc_key.data) free(enc_key.data);
158         return -1;
159 }
160
161 static int
162 prepare_krb5_rfc_cfx_buffer(gss_krb5_lucid_context_v1_t *lctx,
163         gss_buffer_desc *buf, int32_t *endtime)
164 {
165         printerr(0, "ERROR: prepare_krb5_rfc_cfx_buffer: not implemented\n");
166         return -1;
167 }
168
169
170 int
171 serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
172 {
173         OM_uint32 maj_stat, min_stat;
174         void *return_ctx = 0;
175         OM_uint32 vers;
176         gss_krb5_lucid_context_v1_t *lctx = 0;
177         int retcode = 0;
178
179         printerr(2, "DEBUG: serialize_krb5_ctx: lucid version!\n");
180         maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx,
181                                                 1, &return_ctx);
182         if (maj_stat != GSS_S_COMPLETE) {
183                 pgsserr("gss_export_lucid_sec_context",
184                         maj_stat, min_stat, &krb5oid);
185                 goto out_err;
186         }
187
188         /* Check the version returned, we only support v1 right now */
189         vers = ((gss_krb5_lucid_context_version_t *)return_ctx)->version;
190         switch (vers) {
191         case 1:
192                 lctx = (gss_krb5_lucid_context_v1_t *) return_ctx;
193                 break;
194         default:
195                 printerr(0, "ERROR: unsupported lucid sec context version %d\n",
196                         vers);
197                 goto out_err;
198                 break;
199         }
200
201         /* Now lctx points to a lucid context that we can send down to kernel */
202         if (lctx->protocol == 0)
203                 retcode = prepare_krb5_rfc1964_buffer(lctx, buf, endtime);
204         else
205                 retcode = prepare_krb5_rfc_cfx_buffer(lctx, buf, endtime);
206
207         maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx);
208         if (maj_stat != GSS_S_COMPLETE) {
209                 pgsserr("gss_export_lucid_sec_context",
210                         maj_stat, min_stat, &krb5oid);
211                 printerr(0, "WARN: failed to free lucid sec context\n");
212         }
213
214         if (retcode) {
215                 printerr(1, "serialize_krb5_ctx: prepare_krb5_*_buffer "
216                          "failed (retcode = %d)\n", retcode);
217                 goto out_err;
218         }
219
220         return 0;
221
222 out_err:
223         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
224         return -1;
225 }
226 #endif /* HAVE_LUCID_CONTEXT_SUPPORT */