nfs-ganesha 1.4

context_lucid.c

Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT (c) 2006
00003  * The Regents of the University of Michigan
00004  * ALL RIGHTS RESERVED
00005  *
00006  * Permission is granted to use, copy, create derivative works
00007  * and redistribute this software and such derivative works
00008  * for any purpose, so long as the name of The University of
00009  * Michigan is not used in any advertising or publicity
00010  * pertaining to the use of distribution of this software
00011  * without specific, written prior authorization.  If the
00012  * above copyright notice or any other identification of the
00013  * University of Michigan is included in any copy of any
00014  * portion of this software, then the disclaimer below must
00015  * also be included.
00016  *
00017  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
00018  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
00019  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
00020  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
00021  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
00022  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
00023  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
00024  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
00025  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
00026  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
00027  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGES.
00029  */
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif  /* HAVE_CONFIG_H */
00034 
00035 #ifdef HAVE_LUCID_CONTEXT_SUPPORT
00036 
00037 /*
00038  * Newer versions of MIT and Heimdal have lucid context support.
00039  * We can use common code if it is supported.
00040  */
00041 
00042 #include <stdio.h>
00043 #include <syslog.h>
00044 #include <string.h>
00045 #include <errno.h>
00046 
00047 #include <gssapi/gssapi_krb5.h>
00048 
00049 #include "gss_util.h"
00050 #include "gss_oids.h"
00051 #include "err_util.h"
00052 #include "context.h"
00053 
00054 #ifndef OM_uint64
00055 typedef uint64_t OM_uint64;
00056 #endif
00057 
00058 static int
00059 write_lucid_keyblock(char **p, char *end, gss_krb5_lucid_key_t *key)
00060 {
00061         gss_buffer_desc tmp;
00062 
00063         if (WRITE_BYTES(p, end, key->type)) return -1;
00064         tmp.length = key->length;
00065         tmp.value = key->data;
00066         if (write_buffer(p, end, &tmp)) return -1;
00067         return 0;
00068 }
00069 
00070 static int
00071 prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx,
00072         gss_buffer_desc *buf, int32_t *endtime)
00073 {
00074 #define FAKESEED_SIZE 16
00075         char *p, *end;
00076         static int constant_zero = 0;
00077         unsigned char fakeseed[FAKESEED_SIZE];
00078         uint32_t word_send_seq;
00079         gss_krb5_lucid_key_t enc_key;
00080         uint32_t i;
00081         char *skd, *dkd;
00082         gss_buffer_desc fakeoid;
00083 
00084         /*
00085          * The new Kerberos interface to get the gss context
00086          * does not include the seed or seed_init fields
00087          * because we never really use them.  But for now,
00088          * send down a fake buffer so we can use the same
00089          * interface to the kernel.
00090          */
00091         memset(&enc_key, 0, sizeof(enc_key));
00092         memset(&fakeoid, 0, sizeof(fakeoid));
00093         memset(fakeseed, 0, FAKESEED_SIZE);
00094 
00095         if (!(buf->value = calloc(1, MAX_CTX_LEN)))
00096                 goto out_err;
00097         p = buf->value;
00098         end = buf->value + MAX_CTX_LEN;
00099 
00100         if (WRITE_BYTES(&p, end, lctx->initiate)) goto out_err;
00101 
00102         /* seed_init and seed not used by kernel anyway */
00103         if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
00104         if (write_bytes(&p, end, &fakeseed, FAKESEED_SIZE)) goto out_err;
00105 
00106         if (WRITE_BYTES(&p, end, lctx->rfc1964_kd.sign_alg)) goto out_err;
00107         if (WRITE_BYTES(&p, end, lctx->rfc1964_kd.seal_alg)) goto out_err;
00108         if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
00109         if (endtime)
00110                 *endtime = lctx->endtime;
00111         word_send_seq = lctx->send_seq; /* XXX send_seq is 64-bit */
00112         if (WRITE_BYTES(&p, end, word_send_seq)) goto out_err;
00113         if (write_oid(&p, end, &krb5oid)) goto out_err;
00114 
00115 #ifdef HAVE_HEIMDAL
00116         /*
00117          * The kernel gss code expects des-cbc-raw for all flavors of des.
00118          * The keytype from MIT has this type, but Heimdal does not.
00119          * Force the Heimdal keytype to 4 (des-cbc-raw).
00120          * Note that the rfc1964 version only supports DES enctypes.
00121          */
00122         if (lctx->rfc1964_kd.ctx_key.type != 4) {
00123                 printerr(2, "%s: overriding heimdal keytype (%d => %d)\n",
00124                          __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, 4);
00125                 lctx->rfc1964_kd.ctx_key.type = 4;
00126         }
00127 #endif
00128         printerr(2, "%s: serializing keys with enctype %d and length %d\n",
00129                  __FUNCTION__, lctx->rfc1964_kd.ctx_key.type,
00130                  lctx->rfc1964_kd.ctx_key.length);
00131 
00132         /* derive the encryption key and copy it into buffer */
00133         enc_key.type = lctx->rfc1964_kd.ctx_key.type;
00134         enc_key.length = lctx->rfc1964_kd.ctx_key.length;
00135         if ((enc_key.data = calloc(1, enc_key.length)) == NULL)
00136                 goto out_err;
00137         skd = (char *) lctx->rfc1964_kd.ctx_key.data;
00138         dkd = (char *) enc_key.data;
00139         for (i = 0; i < enc_key.length; i++)
00140                 dkd[i] = skd[i] ^ 0xf0;
00141         if (write_lucid_keyblock(&p, end, &enc_key)) {
00142                 free(enc_key.data);
00143                 goto out_err;
00144         }
00145         free(enc_key.data);
00146 
00147         if (write_lucid_keyblock(&p, end, &lctx->rfc1964_kd.ctx_key))
00148                 goto out_err;
00149 
00150         buf->length = p - (char *)buf->value;
00151         return 0;
00152 out_err:
00153         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
00154         if (buf->value) free(buf->value);
00155         buf->length = 0;
00156         if (enc_key.data) free(enc_key.data);
00157         return -1;
00158 }
00159 
00160 /* Flags for version 2 context flags */
00161 #define KRB5_CTX_FLAG_INITIATOR         0x00000001
00162 #define KRB5_CTX_FLAG_CFX               0x00000002
00163 #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
00164 
00165 /*
00166  * Prepare a new-style buffer, as defined in rfc4121 (a.k.a. cfx),
00167  * to send to the kernel for newer encryption types -- or for DES3.
00168  *
00169  * The new format is:
00170  *
00171  *      u32 flags;
00172  *      #define KRB5_CTX_FLAG_INITIATOR         0x00000001
00173  *      #define KRB5_CTX_FLAG_CFX               0x00000002
00174  *      #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
00175  *      s32 endtime;
00176  *      u64 seq_send;
00177  *      u32  enctype;                   ( encrption type of key )
00178  *      raw key;                        ( raw key bytes (kernel will derive))
00179  *
00180  */
00181 static int
00182 prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx,
00183         gss_buffer_desc *buf, int32_t *endtime)
00184 {
00185         char *p, *end;
00186         uint32_t v2_flags = 0;
00187         uint32_t enctype;
00188         uint32_t keysize;
00189 
00190         if (!(buf->value = calloc(1, MAX_CTX_LEN)))
00191                 goto out_err;
00192         p = buf->value;
00193         end = buf->value + MAX_CTX_LEN;
00194 
00195         /* Version 2 */
00196         if (lctx->initiate)
00197                 v2_flags |= KRB5_CTX_FLAG_INITIATOR;
00198         if (lctx->protocol != 0)
00199                 v2_flags |= KRB5_CTX_FLAG_CFX;
00200         if (lctx->protocol != 0 && lctx->cfx_kd.have_acceptor_subkey == 1)
00201                 v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
00202 
00203         if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
00204         if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
00205         if (endtime)
00206                 *endtime = lctx->endtime;
00207         if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err;
00208 
00209         /* Protocol 0 here implies DES3 or RC4 */
00210         printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol);
00211         if (lctx->protocol == 0) {
00212                 enctype = lctx->rfc1964_kd.ctx_key.type;
00213                 keysize = lctx->rfc1964_kd.ctx_key.length;
00214         } else {
00215                 if (lctx->cfx_kd.have_acceptor_subkey) {
00216                         enctype = lctx->cfx_kd.acceptor_subkey.type;
00217                         keysize = lctx->cfx_kd.acceptor_subkey.length;
00218                 } else {
00219                         enctype = lctx->cfx_kd.ctx_key.type;
00220                         keysize = lctx->cfx_kd.ctx_key.length;
00221                 }
00222         }
00223         printerr(2, "%s: serializing key with enctype %d and size %d\n",
00224                  __FUNCTION__, enctype, keysize);
00225 
00226         if (WRITE_BYTES(&p, end, enctype)) goto out_err;
00227 
00228         if (lctx->protocol == 0) {
00229                 if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
00230                                 lctx->rfc1964_kd.ctx_key.length))
00231                         goto out_err;
00232         } else {
00233                 if (lctx->cfx_kd.have_acceptor_subkey) {
00234                         if (write_bytes(&p, end,
00235                                         lctx->cfx_kd.acceptor_subkey.data,
00236                                         lctx->cfx_kd.acceptor_subkey.length))
00237                                 goto out_err;
00238                 } else {
00239                         if (write_bytes(&p, end, lctx->cfx_kd.ctx_key.data,
00240                                         lctx->cfx_kd.ctx_key.length))
00241                                 goto out_err;
00242                 }
00243         }
00244 
00245         buf->length = p - (char *)buf->value;
00246         return 0;
00247 
00248 out_err:
00249         printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n",
00250                  __FUNCTION__);
00251         if (buf->value) {
00252                 free(buf->value);
00253                 buf->value = NULL;
00254         }
00255         buf->length = 0;
00256         return -1;
00257 }
00258 
00259 extern OM_uint32 gss_export_lucid_sec_context(OM_uint32 *min_stat,
00260                                               gss_ctx_id_t *ctx,
00261                                               int val, void *rctx);
00262 
00263 extern OM_uint32 gss_free_lucid_sec_context(OM_uint32 *min_stat,
00264                                             gss_ctx_id_t ctx,
00265                                             void *return_ctx);
00266 
00267 int
00268 serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
00269 {
00270         OM_uint32 maj_stat, min_stat;
00271         void *return_ctx = 0;
00272         OM_uint32 vers;
00273         gss_krb5_lucid_context_v1_t *lctx = 0;
00274         int retcode = 0;
00275 
00276         printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__);
00277         maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx,
00278                                                 1, &return_ctx);
00279         if (maj_stat != GSS_S_COMPLETE) {
00280                 pgsserr("gss_export_lucid_sec_context",
00281                         maj_stat, min_stat, &krb5oid);
00282                 goto out_err;
00283         }
00284 
00285         /* Check the version returned, we only support v1 right now */
00286         vers = ((gss_krb5_lucid_context_version_t *)return_ctx)->version;
00287         switch (vers) {
00288         case 1:
00289                 lctx = (gss_krb5_lucid_context_v1_t *) return_ctx;
00290                 break;
00291         default:
00292                 printerr(0, "ERROR: unsupported lucid sec context version %d\n",
00293                         vers);
00294                 goto out_err;
00295                 break;
00296         }
00297 
00298         /*
00299          * Now lctx points to a lucid context that we can send down to kernel
00300          *
00301          * Note: we send down different information to the kernel depending
00302          * on the protocol version and the enctyption type.
00303          * For protocol version 0 with all enctypes besides DES3, we use
00304          * the original format.  For protocol version != 0 or DES3, we
00305          * send down the new style information.
00306          */
00307 
00308         if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4)
00309                 retcode = prepare_krb5_rfc1964_buffer(lctx, buf, endtime);
00310         else
00311                 retcode = prepare_krb5_rfc4121_buffer(lctx, buf, endtime);
00312 
00313         maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx);
00314         if (maj_stat != GSS_S_COMPLETE) {
00315                 pgsserr("gss_free_lucid_sec_context",
00316                         maj_stat, min_stat, &krb5oid);
00317                 printerr(0, "WARN: failed to free lucid sec context\n");
00318         }
00319 
00320         if (retcode) {
00321                 printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n",
00322                          __FUNCTION__, retcode);
00323                 goto out_err;
00324         }
00325 
00326         return 0;
00327 
00328 out_err:
00329         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
00330         return -1;
00331 }
00332 
00333 
00334 
00335 #endif /* HAVE_LUCID_CONTEXT_SUPPORT */