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