27c44a32c50b758f73a38943228f8e7344e2ff78
[nfs-utils.git] / utils / gssd / context_heimdal.c
1 /*
2   Copyright (c) 2004 The Regents of the University of Michigan.
3   All rights reserved.
4
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions
7   are met:
8
9   1. Redistributions of source code must retain the above copyright
10      notice, this list of conditions and the following disclaimer.
11   2. Redistributions in binary form must reproduce the above copyright
12      notice, this list of conditions and the following disclaimer in the
13      documentation and/or other materials provided with the distribution.
14   3. Neither the name of the University nor the names of its
15      contributors may be used to endorse or promote products derived
16      from this software without specific prior written permission.
17
18   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32
33 #ifdef HAVE_HEIMDAL
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <syslog.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <gssapi.h>
41 #include <krb5.h>
42 #include <com_err.h>
43 #include "err_util.h"
44 #include "gss_oids.h"
45 #include "write_bytes.h"
46
47 #define MAX_CTX_LEN 4096
48
49 int write_heimdal_keyblock(char **p, char *end, krb5_keyblock *key)
50 {
51         gss_buffer_desc tmp;
52         int code = -1;
53
54         if (WRITE_BYTES(p, end, key->keytype)) goto out_err;
55         tmp.length = key->keyvalue.length;
56         tmp.value = key->keyvalue.data;
57         if (write_buffer(p, end, &tmp)) goto out_err;
58         code = 0;
59     out_err:
60         return(code);
61 }
62
63 int write_heimdal_enc_key(char **p, char *end, gss_ctx_id_t ctx)
64 {
65         krb5_keyblock enc_key, *key;
66         krb5_context context;
67         krb5_error_code ret;
68         int i;
69         char *skd, *dkd;
70         int code = -1;
71
72         if ((ret = krb5_init_context(&context))) {
73                 printerr(0, "ERROR: initializing krb5_context: %s\n",
74                         error_message(ret));
75                 goto out_err;
76         }
77
78         if ((ret = krb5_auth_con_getlocalsubkey(context,
79                                                 ctx->auth_context, &key))){
80                 printerr(0, "ERROR: getting auth_context key: %s\n",
81                         error_message(ret));
82                 goto out_err_free_context;
83         }
84
85         memset(&enc_key, 0, sizeof(enc_key));
86         printerr(1, "WARN: write_heimdal_enc_key: "
87                     "overriding heimdal keytype\n");
88         enc_key.keytype = 4 /* XXX XXX XXX XXX key->keytype */;
89         enc_key.keyvalue.length = key->keyvalue.length;
90         if ((enc_key.keyvalue.data =
91                                 calloc(1, enc_key.keyvalue.length)) == NULL) {
92
93                 printerr(0, "ERROR: allocating memory for enc key: %s\n",
94                         error_message(ENOMEM));
95                 goto out_err_free_key;
96         }
97         skd = (char *) key->keyvalue.data;
98         dkd = (char *) enc_key.keyvalue.data;
99         for (i = 0; i < enc_key.keyvalue.length; i++)
100                 dkd[i] = skd[i] ^ 0xf0;
101         if (write_heimdal_keyblock(p, end, &enc_key)) {
102                 goto out_err_free_enckey;
103         }
104
105         code = 0;
106
107     out_err_free_enckey:
108         krb5_free_keyblock_contents(context, &enc_key);
109     out_err_free_key:
110         krb5_free_keyblock(context, key);
111     out_err_free_context:
112         krb5_free_context(context);
113     out_err:
114         printerr(2, "write_heimdal_enc_key: %s\n", code ? "FAILED" : "SUCCESS");
115         return(code);
116 }
117
118 int write_heimdal_seq_key(char **p, char *end, gss_ctx_id_t ctx)
119 {
120         krb5_keyblock *key;
121         krb5_context context;
122         krb5_error_code ret;
123         int code = -1;
124
125         if ((ret = krb5_init_context(&context))) {
126                 printerr(0, "ERROR: initializing krb5_context: %s\n",
127                         error_message(ret));
128                 goto out_err;
129         }
130
131         if ((ret = krb5_auth_con_getlocalsubkey(context,
132                                                 ctx->auth_context, &key))){
133                 printerr(0, "ERROR: getting auth_context key: %s\n",
134                         error_message(ret));
135                 goto out_err_free_context;
136         }
137
138         printerr(1, "WARN: write_heimdal_seq_key: "
139                     "overriding heimdal keytype\n");
140         key->keytype = 4;       /* XXX XXX XXX XXX XXX */
141
142         if (write_heimdal_keyblock(p, end, key)) {
143                 goto out_err_free_key;
144         }
145
146         code = 0;
147
148     out_err_free_key:
149         krb5_free_keyblock(context, key);
150     out_err_free_context:
151         krb5_free_context(context);
152     out_err:
153         printerr(2, "write_heimdal_seq_key: %s\n", code ? "FAILED" : "SUCCESS");
154         return(code);
155 }
156
157 /*
158  * The following is the kernel structure that we are filling in:
159  *
160  * struct krb5_ctx {
161  *         int                     initiate;
162  *         int                     seed_init;
163  *         unsigned char           seed[16];
164  *         int                     signalg;
165  *         int                     sealalg;
166  *         struct crypto_tfm       *enc;
167  *         struct crypto_tfm       *seq;
168  *         s32                     endtime;
169  *         u32                     seq_send;
170  *         struct xdr_netobj       mech_used;
171  * };
172  *
173  * However, note that we do not send the data fields in the
174  * order they appear in the structure.  The order they are
175  * sent down in is:
176  *
177  *      initiate
178  *      seed_init
179  *      seed
180  *      signalg
181  *      sealalg
182  *      endtime
183  *      seq_send
184  *      mech_used
185  *      enc key
186  *      seq key
187  *
188  */
189
190 int
191 serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf)
192 {
193
194         char *p, *end;
195         static int constant_one = 1;
196         static int constant_zero = 0;
197         unsigned char fakeseed[16];
198         uint32_t algorithm;
199
200         if (!(buf->value = calloc(1, MAX_CTX_LEN)))
201                 goto out_err;
202         p = buf->value;
203         end = buf->value + MAX_CTX_LEN;
204
205
206         /* initiate:  1 => initiating 0 => accepting */
207         if (ctx->more_flags & LOCAL) {
208                 if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
209         }
210         else {
211                 if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
212         }
213
214         /* seed_init: not used by kernel code */
215         if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
216
217         /* seed: not used by kernel code */
218         memset(&fakeseed, 0, sizeof(fakeseed));
219         if (write_bytes(&p, end, &fakeseed, 16)) goto out_err;
220
221         /* signalg */
222         algorithm = 0; /* SGN_ALG_DES_MAC_MD5   XXX */
223         if (WRITE_BYTES(&p, end, algorithm)) goto out_err;
224
225         /* sealalg */
226         algorithm = 0; /* SEAL_ALG_DES          XXX */
227         if (WRITE_BYTES(&p, end, algorithm)) goto out_err;
228
229         /* endtime */
230         if (WRITE_BYTES(&p, end, ctx->lifetime)) goto out_err;
231
232         /* seq_send */
233         if (WRITE_BYTES(&p, end, ctx->auth_context->local_seqnumber))
234                 goto out_err;
235         /* mech_used */
236         if (write_buffer(&p, end, (gss_buffer_desc*)&krb5oid)) goto out_err;
237
238         /* enc: derive the encryption key and copy it into buffer */
239         if (write_heimdal_enc_key(&p, end, ctx)) goto out_err;
240
241         /* seq: get the sequence number key and copy it into buffer */
242         if (write_heimdal_seq_key(&p, end, ctx)) goto out_err;
243
244         buf->length = p - (char *)buf->value;
245         printerr(2, "serialize_krb5_ctx: returning buffer "
246                     "with %d bytes\n", buf->length);
247
248         return 0;
249 out_err:
250         printerr(0, "ERROR: failed exporting Heimdal krb5 ctx to kernel\n");
251         if (buf->value) free(buf->value);
252         buf->length = 0;
253         return -1;
254 }
255
256 #endif  /* HAVE_HEIMDAL */