nfs-ganesha 1.4
|
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 */