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