nfs-ganesha 1.4

context_mit.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_KRB5
00037 
00038 #include <stdio.h>
00039 #include <syslog.h>
00040 #include <string.h>
00041 #include <errno.h>
00042 #include <gssapi/gssapi.h>
00043 #include <rpc/rpc.h>
00044 #include <rpc/auth_gss.h>
00045 #include "gss_util.h"
00046 #include "gss_oids.h"
00047 #include "err_util.h"
00048 #include "context.h"
00049 
00050 #include <krb5.h>
00051 
00052 #if (KRB5_VERSION > 131)
00053 /* XXX argggg, there's gotta be a better way than just duplicating this
00054  * whole struct.  Unfortunately, this is in a "private" header file,
00055  * so this is our best choice at this point :-/
00056  */
00057 
00058 typedef struct _krb5_gss_ctx_id_rec {
00059    unsigned int initiate : 1;   /* nonzero if initiating, zero if accepting */
00060    unsigned int established : 1;
00061    unsigned int big_endian : 1;
00062    unsigned int have_acceptor_subkey : 1;
00063    unsigned int seed_init : 1;  /* XXX tested but never actually set */
00064 #ifdef CFX_EXERCISE
00065    unsigned int testing_unknown_tokid : 1; /* for testing only */
00066 #endif
00067    OM_uint32 gss_flags;
00068    unsigned char seed[16];
00069    krb5_principal here;
00070    krb5_principal there;
00071    krb5_keyblock *subkey;
00072    int signalg;
00073    size_t cksum_size;
00074    int sealalg;
00075    krb5_keyblock *enc;
00076    krb5_keyblock *seq;
00077    krb5_timestamp endtime;
00078    krb5_flags krb_flags;
00079    /* XXX these used to be signed.  the old spec is inspecific, and
00080       the new spec specifies unsigned.  I don't believe that the change
00081       affects the wire encoding. */
00082    uint64_t seq_send;           /* gssint_uint64 */
00083    uint64_t seq_recv;           /* gssint_uint64 */
00084    void *seqstate;
00085    krb5_auth_context auth_context;
00086    gss_OID_desc *mech_used;     /* gss_OID_desc */
00087     /* Protocol spec revision
00088        0 => RFC 1964 with 3DES and RC4 enhancements
00089        1 => draft-ietf-krb-wg-gssapi-cfx-01
00090        No others defined so far.  */
00091    int proto;
00092    krb5_cksumtype cksumtype;    /* for "main" subkey */
00093    krb5_keyblock *acceptor_subkey; /* CFX only */
00094    krb5_cksumtype acceptor_subkey_cksumtype;
00095 #ifdef CFX_EXERCISE
00096     gss_buffer_desc init_token;
00097 #endif
00098 } krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t;
00099 
00100 #else   /* KRB5_VERSION > 131 */
00101 
00102 typedef struct _krb5_gss_ctx_id_rec {
00103         int initiate;
00104         u_int32_t gss_flags;
00105         int seed_init;
00106         unsigned char seed[16];
00107         krb5_principal here;
00108         krb5_principal there;
00109         krb5_keyblock *subkey;
00110         int signalg;
00111         int cksum_size;
00112         int sealalg;
00113         krb5_keyblock *enc;
00114         krb5_keyblock *seq;
00115         krb5_timestamp endtime;
00116         krb5_flags krb_flags;
00117         krb5_ui_4 seq_send;
00118         krb5_ui_4 seq_recv;
00119         void *seqstate;
00120         int established;
00121         int big_endian;
00122         krb5_auth_context auth_context;
00123         gss_OID_desc *mech_used;
00124         int nctypes;
00125         krb5_cksumtype *ctypes;
00126 } krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t;
00127 
00128 #endif /* KRB5_VERSION */
00129 
00130 
00131 static int
00132 write_keyblock(char **p, char *end, struct _krb5_keyblock *arg)
00133 {
00134         gss_buffer_desc tmp;
00135 
00136         if (WRITE_BYTES(p, end, arg->enctype)) return -1;
00137         tmp.length = arg->length;
00138         tmp.value = arg->contents;
00139         if (write_buffer(p, end, &tmp)) return -1;
00140         return 0;
00141 }
00142 
00143 /*
00144  * We really shouldn't know about glue-layer context structure, but
00145  * we need to get at the real krb5 context pointer.  This should be
00146  * removed as soon as we say there is no support for MIT Kerberos
00147  * prior to 1.4 -- which gives us "legal" access to the context info.
00148  */
00149 typedef struct gss_union_ctx_id_t {
00150         gss_OID         mech_type;
00151         gss_ctx_id_t    internal_ctx_id;
00152 } gss_union_ctx_id_desc, *gss_union_ctx_id_t;
00153 
00154 int
00155 serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
00156 {
00157         krb5_gss_ctx_id_t kctx = (krb5_gss_ctx_id_t) ((gss_union_ctx_id_t)ctx)->internal_ctx_id;
00158         char *p, *end;
00159         static int constant_zero = 0;
00160         static int constant_one = 1;
00161         static int constant_two __attribute__((unused)) = 2;
00162         uint32_t word_seq_send;
00163         u_int64_t seq_send_64bit;
00164         uint32_t v2_flags = 0;
00165 
00166         if (!(buf->value = calloc(1, MAX_CTX_LEN)))
00167                 goto out_err;
00168         p = buf->value;
00169         end = buf->value + MAX_CTX_LEN;
00170 
00171         switch (kctx->enc->enctype) {
00172         case ENCTYPE_DES_CBC_CRC:
00173         case ENCTYPE_DES_CBC_MD4:
00174         case ENCTYPE_DES_CBC_MD5:
00175         case ENCTYPE_DES_CBC_RAW:
00176                 /* Old format of context to the kernel */
00177                 if (kctx->initiate) {
00178                         if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
00179                 }
00180                 else {
00181                         if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
00182                 }
00183                 if (kctx->seed_init) {
00184                         if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
00185                 }
00186                 else {
00187                         if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
00188                 }
00189                 if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
00190                         goto out_err;
00191                 if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err;
00192                 if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err;
00193                 if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
00194                 if (endtime)
00195                         *endtime = kctx->endtime;
00196                 word_seq_send = kctx->seq_send;
00197                 if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err;
00198                 if (write_oid(&p, end, kctx->mech_used)) goto out_err;
00199 
00200                 printerr(2, "serialize_krb5_ctx: serializing keys with "
00201                          "enctype %d and length %d\n",
00202                          kctx->enc->enctype, kctx->enc->length);
00203 
00204                 if (write_keyblock(&p, end, kctx->enc)) goto out_err;
00205                 if (write_keyblock(&p, end, kctx->seq)) goto out_err;
00206                 break;
00207         case ENCTYPE_DES3_CBC_RAW:
00208         case ENCTYPE_DES3_CBC_SHA1:
00209         case ENCTYPE_ARCFOUR_HMAC:
00210         case ENCTYPE_ARCFOUR_HMAC_EXP:
00211         case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
00212         case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
00213                 /* New format of context to the kernel */
00214                 /* u32 flags;
00215                  * #define KRB5_CTX_FLAG_INITIATOR        0x00000001
00216                  * #define KRB5_CTX_FLAG_CFX              0x00000002
00217                  * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY  0x00000004
00218                  * s32 endtime;
00219                  * u64 seq_send;
00220                  * u32  enctype;
00221                  * rawkey data
00222                  */
00223 
00224                 if (kctx->initiate)
00225                         v2_flags |= KRB5_CTX_FLAG_INITIATOR;
00226                 if (kctx->proto == 1)
00227                         v2_flags |= KRB5_CTX_FLAG_CFX;
00228                 if (kctx->have_acceptor_subkey)
00229                         v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
00230                 if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
00231                 if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
00232 
00233                 seq_send_64bit = kctx->seq_send;
00234                 if (WRITE_BYTES(&p, end, seq_send_64bit)) goto out_err;
00235 
00236                 if (kctx->have_acceptor_subkey) {
00237                         if (WRITE_BYTES(&p, end, kctx->acceptor_subkey->enctype))
00238                                 goto out_err;
00239                         printerr(2, "serialize_krb5_ctx: serializing subkey "
00240                                  "with enctype %d and size %d\n",
00241                                  kctx->acceptor_subkey->enctype,
00242                                  kctx->acceptor_subkey->length);
00243 
00244                         if (write_bytes(&p, end,
00245                                         kctx->acceptor_subkey->contents,
00246                                         kctx->acceptor_subkey->length))
00247                                 goto out_err;
00248                 } else {
00249                         if (WRITE_BYTES(&p, end, kctx->enc->enctype))
00250                                 goto out_err;
00251                         printerr(2, "serialize_krb5_ctx: serializing key "
00252                                  "with enctype %d and size %d\n",
00253                                  kctx->enc->enctype, kctx->enc->length);
00254 
00255                         if (write_bytes(&p, end, kctx->enc->contents,
00256                                         kctx->enc->length))
00257                                 goto out_err;
00258                 }
00259                 break;
00260         default:
00261                 printerr(0, "ERROR: serialize_krb5_ctx: unsupported encryption "
00262                          "algorithm %d\n", kctx->enc->enctype);
00263                 goto out_err;
00264         }
00265 
00266         buf->length = p - (char *)buf->value;
00267         return 0;
00268 
00269 out_err:
00270         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
00271         if (buf->value) {
00272                 free(buf->value);
00273         }
00274         buf->value = NULL;
00275         buf->length = 0;
00276         return -1;
00277 }
00278 
00279 #endif /* HAVE_KRB5 */
00280 #endif /* HAVE_LUCID_CONTEXT_SUPPORT */