nfs-ganesha 1.4

context_heimdal.c

Go to the documentation of this file.
00001 /*
00002   Copyright (c) 2004-2006 The Regents of the University of Michigan.
00003   All rights reserved.
00004 
00005   Redistribution and use in source and binary forms, with or without
00006   modification, are permitted provided that the following conditions
00007   are met:
00008 
00009   1. Redistributions of source code must retain the above copyright
00010      notice, this list of conditions and the following disclaimer.
00011   2. Redistributions in binary form must reproduce the above copyright
00012      notice, this list of conditions and the following disclaimer in the
00013      documentation and/or other materials provided with the distribution.
00014   3. Neither the name of the University nor the names of its
00015      contributors may be used to endorse or promote products derived
00016      from this software without specific prior written permission.
00017 
00018   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
00019   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00020   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00021   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00022   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
00025   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00026   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00027   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 */
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif  /* HAVE_CONFIG_H */
00034 
00035 #ifndef HAVE_LUCID_CONTEXT_SUPPORT
00036 #ifdef HAVE_HEIMDAL
00037 
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <syslog.h>
00041 #include <string.h>
00042 #include <errno.h>
00043 #include <krb5.h>
00044 #include <gssapi.h>     /* Must use the heimdal copy! */
00045 #ifdef HAVE_COM_ERR_H
00046 #include <com_err.h>
00047 #endif
00048 #include "err_util.h"
00049 #include "gss_oids.h"
00050 #include "write_bytes.h"
00051 
00052 int write_heimdal_keyblock(char **p, char *end, krb5_keyblock *key)
00053 {
00054         gss_buffer_desc tmp;
00055         int code = -1;
00056 
00057         if (WRITE_BYTES(p, end, key->keytype)) goto out_err;
00058         tmp.length = key->keyvalue.length;
00059         tmp.value = key->keyvalue.data;
00060         if (write_buffer(p, end, &tmp)) goto out_err;
00061         code = 0;
00062     out_err:
00063         return(code);
00064 }
00065 
00066 int write_heimdal_enc_key(char **p, char *end, gss_ctx_id_t ctx)
00067 {
00068         krb5_keyblock enc_key, *key;
00069         krb5_context context;
00070         krb5_error_code ret;
00071         int i;
00072         char *skd, *dkd, *k5err = NULL;
00073         int code = -1;
00074 
00075         if ((ret = krb5_init_context(&context))) {
00076                 k5err = gssd_k5_err_msg(NULL, ret);
00077                 printerr(0, "ERROR: initializing krb5_context: %s\n", k5err);
00078                 goto out_err;
00079         }
00080 
00081         if ((ret = krb5_auth_con_getlocalsubkey(context,
00082                                                 ctx->auth_context, &key))){
00083                 k5err = gssd_k5_err_msg(context, ret);
00084                 printerr(0, "ERROR: getting auth_context key: %s\n", k5err);
00085                 goto out_err_free_context;
00086         }
00087 
00088         memset(&enc_key, 0, sizeof(enc_key));
00089         enc_key.keytype = key->keytype;
00090         /* XXX current kernel code only handles des-cbc-raw  (4) */
00091         if (enc_key.keytype != 4) {
00092                 printerr(1, "WARN: write_heimdal_enc_key: "
00093                             "overriding heimdal keytype (%d => %d)\n",
00094                          enc_key.keytype, 4);
00095                 enc_key.keytype = 4;
00096         }
00097         enc_key.keyvalue.length = key->keyvalue.length;
00098         if ((enc_key.keyvalue.data =
00099                                 calloc(1, enc_key.keyvalue.length)) == NULL) {
00100                 k5err = gssd_k5_err_msg(context, ENOMEM);
00101                 printerr(0, "ERROR: allocating memory for enc key: %s\n",
00102                          k5err);
00103                 goto out_err_free_key;
00104         }
00105         skd = (char *) key->keyvalue.data;
00106         dkd = (char *) enc_key.keyvalue.data;
00107         for (i = 0; i < enc_key.keyvalue.length; i++)
00108                 dkd[i] = skd[i] ^ 0xf0;
00109         if (write_heimdal_keyblock(p, end, &enc_key)) {
00110                 goto out_err_free_enckey;
00111         }
00112 
00113         code = 0;
00114 
00115     out_err_free_enckey:
00116         krb5_free_keyblock_contents(context, &enc_key);
00117     out_err_free_key:
00118         krb5_free_keyblock(context, key);
00119     out_err_free_context:
00120         krb5_free_context(context);
00121     out_err:
00122         free(k5err);
00123         printerr(2, "write_heimdal_enc_key: %s\n", code ? "FAILED" : "SUCCESS");
00124         return(code);
00125 }
00126 
00127 int write_heimdal_seq_key(char **p, char *end, gss_ctx_id_t ctx)
00128 {
00129         krb5_keyblock *key;
00130         krb5_context context;
00131         krb5_error_code ret;
00132         char *k5err = NULL;
00133         int code = -1;
00134 
00135         if ((ret = krb5_init_context(&context))) {
00136                 k5err = gssd_k5_err_msg(NULL, ret);
00137                 printerr(0, "ERROR: initializing krb5_context: %s\n", k5err);
00138                 goto out_err;
00139         }
00140 
00141         if ((ret = krb5_auth_con_getlocalsubkey(context,
00142                                                 ctx->auth_context, &key))){
00143                 k5err = gssd_k5_err_msg(context, ret);
00144                 printerr(0, "ERROR: getting auth_context key: %s\n", k5err);
00145                 goto out_err_free_context;
00146         }
00147 
00148         /* XXX current kernel code only handles des-cbc-raw  (4) */
00149         if (key->keytype != 4) {
00150                 printerr(1, "WARN: write_heimdal_seq_key: "
00151                             "overriding heimdal keytype (%d => %d)\n",
00152                          key->keytype, 4);
00153                 key->keytype = 4;
00154         }
00155 
00156         if (write_heimdal_keyblock(p, end, key)) {
00157                 goto out_err_free_key;
00158         }
00159 
00160         code = 0;
00161 
00162     out_err_free_key:
00163         krb5_free_keyblock(context, key);
00164     out_err_free_context:
00165         krb5_free_context(context);
00166     out_err:
00167         free(k5err);
00168         printerr(2, "write_heimdal_seq_key: %s\n", code ? "FAILED" : "SUCCESS");
00169         return(code);
00170 }
00171 
00172 /*
00173  * The following is the kernel structure that we are filling in:
00174  *
00175  * struct krb5_ctx {
00176  *         int                     initiate;
00177  *         int                     seed_init;
00178  *         unsigned char           seed[16];
00179  *         int                     signalg;
00180  *         int                     sealalg;
00181  *         struct crypto_tfm       *enc;
00182  *         struct crypto_tfm       *seq;
00183  *         s32                     endtime;
00184  *         u32                     seq_send;
00185  *         struct xdr_netobj       mech_used;
00186  * };
00187  *
00188  * However, note that we do not send the data fields in the
00189  * order they appear in the structure.  The order they are
00190  * sent down in is:
00191  *
00192  *      initiate
00193  *      seed_init
00194  *      seed
00195  *      signalg
00196  *      sealalg
00197  *      endtime
00198  *      seq_send
00199  *      mech_used
00200  *      enc key
00201  *      seq key
00202  *
00203  */
00204 
00205 int
00206 serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
00207 {
00208 
00209         char *p, *end;
00210         static int constant_one = 1;
00211         static int constant_zero = 0;
00212         unsigned char fakeseed[16];
00213         uint32_t algorithm;
00214 
00215         if (!(buf->value = calloc(1, MAX_CTX_LEN)))
00216                 goto out_err;
00217         p = buf->value;
00218         end = buf->value + MAX_CTX_LEN;
00219 
00220 
00221         /* initiate:  1 => initiating 0 => accepting */
00222         if (ctx->more_flags & LOCAL) {
00223                 if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
00224         }
00225         else {
00226                 if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
00227         }
00228 
00229         /* seed_init: not used by kernel code */
00230         if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
00231 
00232         /* seed: not used by kernel code */
00233         memset(&fakeseed, 0, sizeof(fakeseed));
00234         if (write_bytes(&p, end, &fakeseed, 16)) goto out_err;
00235 
00236         /* signalg */
00237         algorithm = 0; /* SGN_ALG_DES_MAC_MD5   XXX */
00238         if (WRITE_BYTES(&p, end, algorithm)) goto out_err;
00239 
00240         /* sealalg */
00241         algorithm = 0; /* SEAL_ALG_DES          XXX */
00242         if (WRITE_BYTES(&p, end, algorithm)) goto out_err;
00243 
00244         /* endtime */
00245         if (WRITE_BYTES(&p, end, ctx->lifetime)) goto out_err;
00246 
00247         if (endtime)
00248                 *endtime = ctx->lifetime;
00249 
00250         /* seq_send */
00251         if (WRITE_BYTES(&p, end, ctx->auth_context->local_seqnumber))
00252                 goto out_err;
00253         /* mech_used */
00254         if (write_buffer(&p, end, (gss_buffer_desc*)&krb5oid)) goto out_err;
00255 
00256         /* enc: derive the encryption key and copy it into buffer */
00257         if (write_heimdal_enc_key(&p, end, ctx)) goto out_err;
00258 
00259         /* seq: get the sequence number key and copy it into buffer */
00260         if (write_heimdal_seq_key(&p, end, ctx)) goto out_err;
00261 
00262         buf->length = p - (char *)buf->value;
00263         printerr(2, "serialize_krb5_ctx: returning buffer "
00264                     "with %d bytes\n", buf->length);
00265 
00266         return 0;
00267 out_err:
00268         printerr(0, "ERROR: failed exporting Heimdal krb5 ctx to kernel\n");
00269         if (buf->value) free(buf->value);
00270         buf->length = 0;
00271         return -1;
00272 }
00273 
00274 #endif  /* HAVE_HEIMDAL */
00275 #endif  /* HAVE_LUCID_CONTEXT_SUPPORT */