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