5520cbcc61d15850b16f9d249ed28de139f2a41c
[nfs-utils.git] / utils / gssd / context_heimdal.c
1 /*
2   Copyright (c) 2004-2006 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 #ifndef HAVE_LUCID_CONTEXT_SUPPORT
34 #ifdef HAVE_HEIMDAL
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <syslog.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <krb5.h>
42 #include <gssapi.h>     /* Must use the heimdal copy! */
43 #ifdef HAVE_COM_ERR_H
44 #include <com_err.h>
45 #endif
46 #include "err_util.h"
47 #include "gss_oids.h"
48 #include "write_bytes.h"
49
50 int write_heimdal_keyblock(char **p, char *end, krb5_keyblock *key)
51 {
52         gss_buffer_desc tmp;
53         int code = -1;
54
55         if (WRITE_BYTES(p, end, key->keytype)) goto out_err;
56         tmp.length = key->keyvalue.length;
57         tmp.value = key->keyvalue.data;
58         if (write_buffer(p, end, &tmp)) goto out_err;
59         code = 0;
60     out_err:
61         return(code);
62 }
63
64 int write_heimdal_enc_key(char **p, char *end, gss_ctx_id_t ctx)
65 {
66         krb5_keyblock enc_key, *key;
67         krb5_context context;
68         krb5_error_code ret;
69         int i;
70         char *skd, *dkd;
71         int code = -1;
72
73         if ((ret = krb5_init_context(&context))) {
74                 printerr(0, "ERROR: initializing krb5_context: %s\n",
75                         error_message(ret));
76                 goto out_err;
77         }
78
79         if ((ret = krb5_auth_con_getlocalsubkey(context,
80                                                 ctx->auth_context, &key))){
81                 printerr(0, "ERROR: getting auth_context key: %s\n",
82                         error_message(ret));
83                 goto out_err_free_context;
84         }
85
86         memset(&enc_key, 0, sizeof(enc_key));
87         enc_key.keytype = key->keytype;
88         /* XXX current kernel code only handles des-cbc-raw  (4) */
89         if (enc_key.keytype != 4) {
90                 printerr(1, "WARN: write_heimdal_enc_key: "
91                             "overriding heimdal keytype (%d => %d)\n",
92                          enc_key.keytype, 4);
93                 enc_key.keytype = 4;
94         }
95         enc_key.keyvalue.length = key->keyvalue.length;
96         if ((enc_key.keyvalue.data =
97                                 calloc(1, enc_key.keyvalue.length)) == NULL) {
98
99                 printerr(0, "ERROR: allocating memory for enc key: %s\n",
100                         error_message(ENOMEM));
101                 goto out_err_free_key;
102         }
103         skd = (char *) key->keyvalue.data;
104         dkd = (char *) enc_key.keyvalue.data;
105         for (i = 0; i < enc_key.keyvalue.length; i++)
106                 dkd[i] = skd[i] ^ 0xf0;
107         if (write_heimdal_keyblock(p, end, &enc_key)) {
108                 goto out_err_free_enckey;
109         }
110
111         code = 0;
112
113     out_err_free_enckey:
114         krb5_free_keyblock_contents(context, &enc_key);
115     out_err_free_key:
116         krb5_free_keyblock(context, key);
117     out_err_free_context:
118         krb5_free_context(context);
119     out_err:
120         printerr(2, "write_heimdal_enc_key: %s\n", code ? "FAILED" : "SUCCESS");
121         return(code);
122 }
123
124 int write_heimdal_seq_key(char **p, char *end, gss_ctx_id_t ctx)
125 {
126         krb5_keyblock *key;
127         krb5_context context;
128         krb5_error_code ret;
129         int code = -1;
130
131         if ((ret = krb5_init_context(&context))) {
132                 printerr(0, "ERROR: initializing krb5_context: %s\n",
133                         error_message(ret));
134                 goto out_err;
135         }
136
137         if ((ret = krb5_auth_con_getlocalsubkey(context,
138                                                 ctx->auth_context, &key))){
139                 printerr(0, "ERROR: getting auth_context key: %s\n",
140                         error_message(ret));
141                 goto out_err_free_context;
142         }
143
144         /* XXX current kernel code only handles des-cbc-raw  (4) */
145         if (key->keytype != 4) {
146                 printerr(1, "WARN: write_heimdal_seq_key: "
147                             "overriding heimdal keytype (%d => %d)\n",
148                          key->keytype, 4);
149                 key->keytype = 4;
150         }
151
152         if (write_heimdal_keyblock(p, end, key)) {
153                 goto out_err_free_key;
154         }
155
156         code = 0;
157
158     out_err_free_key:
159         krb5_free_keyblock(context, key);
160     out_err_free_context:
161         krb5_free_context(context);
162     out_err:
163         printerr(2, "write_heimdal_seq_key: %s\n", code ? "FAILED" : "SUCCESS");
164         return(code);
165 }
166
167 /*
168  * The following is the kernel structure that we are filling in:
169  *
170  * struct krb5_ctx {
171  *         int                     initiate;
172  *         int                     seed_init;
173  *         unsigned char           seed[16];
174  *         int                     signalg;
175  *         int                     sealalg;
176  *         struct crypto_tfm       *enc;
177  *         struct crypto_tfm       *seq;
178  *         s32                     endtime;
179  *         u32                     seq_send;
180  *         struct xdr_netobj       mech_used;
181  * };
182  *
183  * However, note that we do not send the data fields in the
184  * order they appear in the structure.  The order they are
185  * sent down in is:
186  *
187  *      initiate
188  *      seed_init
189  *      seed
190  *      signalg
191  *      sealalg
192  *      endtime
193  *      seq_send
194  *      mech_used
195  *      enc key
196  *      seq key
197  *
198  */
199
200 int
201 serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf)
202 {
203
204         char *p, *end;
205         static int constant_one = 1;
206         static int constant_zero = 0;
207         unsigned char fakeseed[16];
208         uint32_t algorithm;
209
210         if (!(buf->value = calloc(1, MAX_CTX_LEN)))
211                 goto out_err;
212         p = buf->value;
213         end = buf->value + MAX_CTX_LEN;
214
215
216         /* initiate:  1 => initiating 0 => accepting */
217         if (ctx->more_flags & LOCAL) {
218                 if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
219         }
220         else {
221                 if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
222         }
223
224         /* seed_init: not used by kernel code */
225         if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
226
227         /* seed: not used by kernel code */
228         memset(&fakeseed, 0, sizeof(fakeseed));
229         if (write_bytes(&p, end, &fakeseed, 16)) goto out_err;
230
231         /* signalg */
232         algorithm = 0; /* SGN_ALG_DES_MAC_MD5   XXX */
233         if (WRITE_BYTES(&p, end, algorithm)) goto out_err;
234
235         /* sealalg */
236         algorithm = 0; /* SEAL_ALG_DES          XXX */
237         if (WRITE_BYTES(&p, end, algorithm)) goto out_err;
238
239         /* endtime */
240         if (WRITE_BYTES(&p, end, ctx->lifetime)) goto out_err;
241
242         /* seq_send */
243         if (WRITE_BYTES(&p, end, ctx->auth_context->local_seqnumber))
244                 goto out_err;
245         /* mech_used */
246         if (write_buffer(&p, end, (gss_buffer_desc*)&krb5oid)) goto out_err;
247
248         /* enc: derive the encryption key and copy it into buffer */
249         if (write_heimdal_enc_key(&p, end, ctx)) goto out_err;
250
251         /* seq: get the sequence number key and copy it into buffer */
252         if (write_heimdal_seq_key(&p, end, ctx)) goto out_err;
253
254         buf->length = p - (char *)buf->value;
255         printerr(2, "serialize_krb5_ctx: returning buffer "
256                     "with %d bytes\n", buf->length);
257
258         return 0;
259 out_err:
260         printerr(0, "ERROR: failed exporting Heimdal krb5 ctx to kernel\n");
261         if (buf->value) free(buf->value);
262         buf->length = 0;
263         return -1;
264 }
265
266 #endif  /* HAVE_HEIMDAL */
267 #endif  /* HAVE_LUCID_CONTEXT_SUPPORT */