]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/gssd/context_lucid.c
Fix the usage message for gssd to reflect new option
[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)
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         word_send_seq = lctx->send_seq; /* XXX send_seq is 64-bit */
105         if (WRITE_BYTES(&p, end, word_send_seq)) goto out_err;
106         if (write_oid(&p, end, &krb5oid)) goto out_err;
107
108 #ifdef HAVE_HEIMDAL
109         /*
110          * The kernel gss code expects des-cbc-raw for all flavors of des.
111          * The keytype from MIT has this type, but Heimdal does not.
112          * Force the Heimdal keytype to 4 (des-cbc-raw).
113          * Note that the rfc1964 version only supports DES enctypes.
114          */
115         if (lctx->rfc1964_kd.ctx_key.type != 4) {
116                 printerr(1, "prepare_krb5_rfc1964_buffer: "
117                             "overriding heimdal keytype (%d => %d)\n",
118                             lctx->rfc1964_kd.ctx_key.type, 4);
119                 lctx->rfc1964_kd.ctx_key.type = 4;
120         }
121 #endif
122         printerr(2, "prepare_krb5_rfc1964_buffer: serializing keys with "
123                  "enctype %d and length %d\n",
124                  lctx->rfc1964_kd.ctx_key.type,
125                  lctx->rfc1964_kd.ctx_key.length);
126
127         /* derive the encryption key and copy it into buffer */
128         enc_key.type = lctx->rfc1964_kd.ctx_key.type;
129         enc_key.length = lctx->rfc1964_kd.ctx_key.length;
130         if ((enc_key.data = calloc(1, enc_key.length)) == NULL)
131                 goto out_err;
132         skd = (char *) lctx->rfc1964_kd.ctx_key.data;
133         dkd = (char *) enc_key.data;
134         for (i = 0; i < enc_key.length; i++)
135                 dkd[i] = skd[i] ^ 0xf0;
136         if (write_lucid_keyblock(&p, end, &enc_key)) {
137                 free(enc_key.data);
138                 goto out_err;
139         }
140         free(enc_key.data);
141
142         if (write_lucid_keyblock(&p, end, &lctx->rfc1964_kd.ctx_key))
143                 goto out_err;
144
145         buf->length = p - (char *)buf->value;
146         return 0;
147 out_err:
148         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
149         if (buf->value) free(buf->value);
150         buf->length = 0;
151         if (enc_key.data) free(enc_key.data);
152         return -1;
153 }
154
155 static int
156 prepare_krb5_rfc_cfx_buffer(gss_krb5_lucid_context_v1_t *lctx,
157         gss_buffer_desc *buf)
158 {
159         printerr(0, "ERROR: prepare_krb5_rfc_cfx_buffer: not implemented\n");
160         return -1;
161 }
162
163
164 int
165 serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf)
166 {
167         OM_uint32 maj_stat, min_stat;
168         void *return_ctx = 0;
169         OM_uint32 vers;
170         gss_krb5_lucid_context_v1_t *lctx = 0;
171         int retcode = 0;
172
173         printerr(2, "DEBUG: serialize_krb5_ctx: lucid version!\n");
174         maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx,
175                                                 1, &return_ctx);
176         if (maj_stat != GSS_S_COMPLETE) {
177                 pgsserr("gss_export_lucid_sec_context",
178                         maj_stat, min_stat, &krb5oid);
179                 goto out_err;
180         }
181
182         /* Check the version returned, we only support v1 right now */
183         vers = ((gss_krb5_lucid_context_version_t *)return_ctx)->version;
184         switch (vers) {
185         case 1:
186                 lctx = (gss_krb5_lucid_context_v1_t *) return_ctx;
187                 break;
188         default:
189                 printerr(0, "ERROR: unsupported lucid sec context version %d\n",
190                         vers);
191                 goto out_err;
192                 break;
193         }
194
195         /* Now lctx points to a lucid context that we can send down to kernel */
196         if (lctx->protocol == 0)
197                 retcode = prepare_krb5_rfc1964_buffer(lctx, buf);
198         else
199                 retcode = prepare_krb5_rfc_cfx_buffer(lctx, buf);
200
201         maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx);
202         if (maj_stat != GSS_S_COMPLETE) {
203                 pgsserr("gss_export_lucid_sec_context",
204                         maj_stat, min_stat, &krb5oid);
205                 printerr(0, "WARN: failed to free lucid sec context\n");
206         }
207
208         if (retcode) {
209                 printerr(1, "serialize_krb5_ctx: prepare_krb5_*_buffer "
210                          "failed (retcode = %d)\n", retcode);
211                 goto out_err;
212         }
213
214         return 0;
215
216 out_err:
217         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
218         return -1;
219 }
220 #endif /* HAVE_LUCID_CONTEXT_SUPPORT */