nfs-ganesha 1.4
|
00001 #ifdef HAVE_CONFIG_H 00002 #include "config.h" 00003 #endif 00004 00005 #ifdef _SOLARIS 00006 #include "solaris_port.h" 00007 #endif 00008 00009 #include <stdio.h> 00010 #include <stdlib.h> 00011 #include <string.h> 00012 00013 #include "HashData.h" 00014 #include "HashTable.h" 00015 #include "log.h" 00016 #include "config_parsing.h" 00017 #include "nfs_core.h" 00018 00019 #include "rpcal.h" 00020 #ifdef HAVE_HEIMDAL 00021 #include <gssapi.h> 00022 #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE 00023 #else 00024 #include <gssapi/gssapi.h> 00025 #include <gssapi/gssapi_generic.h> 00026 #endif 00027 00028 #define GSS_CNAMELEN 1024 00029 #define GSS_CKSUM_LEN 1024 00030 00031 struct svc_rpc_gss_data_stored 00032 { 00033 bool_t established; 00034 gss_buffer_desc ctx_exported; 00035 struct rpc_gss_sec sec; 00036 char cname_val[GSS_CNAMELEN]; 00037 size_t cname_len; 00038 u_int seq; 00039 u_int win; 00040 u_int seqlast; 00041 uint32_t seqmask; 00042 gss_name_t client_name; 00043 char checksum_val[GSS_CKSUM_LEN]; 00044 size_t checksum_len; 00045 }; 00046 00059 static const char *gss_data2stored(struct svc_rpc_gss_data *gd, 00060 struct svc_rpc_gss_data_stored *pstored) 00061 { 00062 OM_uint32 major; 00063 OM_uint32 minor; 00064 00065 /* Save the data with a fixed size */ 00066 pstored->established = gd->established; 00067 pstored->sec = gd->sec; 00068 pstored->seq = gd->seq; 00069 pstored->win = gd->win; 00070 pstored->seqlast = gd->seqlast; 00071 pstored->seqmask = gd->seqmask; 00072 00073 /* keep the gss_buffer_desc */ 00074 memcpy(pstored->cname_val, gd->cname.value, gd->cname.length); 00075 pstored->cname_len = gd->cname.length; 00076 00077 memcpy(pstored->checksum_val, gd->checksum.value, gd->checksum.length); 00078 pstored->checksum_len = gd->checksum.length; 00079 00080 /* Duplicate the gss_name */ 00081 if((major = gss_duplicate_name(&minor, 00082 gd->client_name, 00083 &pstored->client_name)) != GSS_S_COMPLETE) 00084 return "could not duplicate client_name"; 00085 00086 /* export the sec context */ 00087 if((major = gss_export_sec_context(&minor, 00088 &gd->ctx, &pstored->ctx_exported)) != GSS_S_COMPLETE) 00089 return "could not export context"; 00090 00091 return NULL; 00092 } /* gss_data2stored */ 00093 00106 static const char *gss_stored2data(struct svc_rpc_gss_data *gd, 00107 struct svc_rpc_gss_data_stored *pstored) 00108 { 00109 OM_uint32 major; 00110 OM_uint32 minor; 00111 00112 /* Get the data with a fixed size */ 00113 gd->established = pstored->established; 00114 gd->sec = pstored->sec; 00115 gd->seq = pstored->seq; 00116 gd->win = pstored->win; 00117 gd->seqlast = pstored->seqlast; 00118 gd->seqmask = pstored->seqmask; 00119 00120 /* Get the gss_buffer_desc */ 00121 if(gd->cname.length <= pstored->cname_len && gd->cname.length != 0) 00122 { 00123 /* If the current buffer is too small, release it */ 00124 LogFullDebug(COMPONENT_RPCSEC_GSS, 00125 "gss_stored2data releasing cname.value=%p length was %d need %d", 00126 gd->cname.value, (int)gd->cname.length, (int)pstored->cname_len); 00127 gss_release_buffer(&minor, &gd->cname); 00128 } 00129 if(gd->cname.value == NULL) 00130 { 00131 if(pstored->cname_len != 0) 00132 { 00133 if((gd->cname.value = (void *)malloc(pstored->cname_len+1)) == NULL) 00134 return "could not allocate cname"; 00135 } 00136 else 00137 return "could not allocate cname"; 00138 } 00139 memcpy(gd->cname.value, pstored->cname_val, pstored->cname_len); 00140 ((char *)gd->cname.value)[pstored->cname_len] = '\0'; 00141 gd->cname.length = pstored->cname_len; 00142 00143 if(gd->checksum.length < pstored->checksum_len && gd->checksum.length != 0) 00144 { 00145 /* If the current buffer is too small, release it */ 00146 LogFullDebug(COMPONENT_RPCSEC_GSS, 00147 "gss_stored2data releasing checksum.value=%p length was %d need %d", 00148 gd->checksum.value, (int)gd->checksum.length, (int)pstored->checksum_len); 00149 gss_release_buffer(&minor, &gd->checksum); 00150 } 00151 if(gd->checksum.value == NULL && pstored->checksum_len != 0) 00152 { 00153 if((gd->checksum.value = (char *)malloc(pstored->checksum_len)) == NULL) 00154 return "could not allocate checksum"; 00155 } 00156 memcpy(gd->checksum.value, pstored->checksum_val, pstored->checksum_len); 00157 gd->checksum.length = pstored->checksum_len; 00158 00159 /* Duplicate the gss_name */ 00160 if(gd->client_name) 00161 { 00162 LogFullDebug(COMPONENT_RPCSEC_GSS, 00163 "gss_stored2data releasing client_name=%p", 00164 gd->client_name); 00165 gss_release_name(&minor, &gd->client_name); 00166 } 00167 if((major = gss_duplicate_name(&minor, 00168 pstored->client_name, 00169 &gd->client_name)) != GSS_S_COMPLETE) 00170 return "could not duplicate client_name"; 00171 00172 /* Import the sec context */ 00173 gss_delete_sec_context(&minor, &gd->ctx, GSS_C_NO_BUFFER); 00174 if((major = gss_import_sec_context(&minor, 00175 &pstored->ctx_exported, &gd->ctx)) != GSS_S_COMPLETE) 00176 return "could not import context"; 00177 00178 return NULL; 00179 } /* gss_stored2data */ 00180 00181 hash_table_t *ht_gss_ctx; 00182 00198 uint32_t gss_ctx_hash_func(hash_parameter_t * p_hparam, hash_buffer_t * buffclef) 00199 { 00200 unsigned long hash_func; 00201 gss_union_ctx_id_desc *pgss_ctx; 00202 00203 pgss_ctx = (gss_union_ctx_id_desc *) (buffclef->pdata); 00204 00205 /* The gss context is basically made of two address in memory: one for the gss mech and one for the 00206 * mech's specific data for this context */ 00207 hash_func = 00208 (unsigned long)pgss_ctx->mech_type + (unsigned long)pgss_ctx->internal_ctx_id; 00209 00210 if(isFullDebug(COMPONENT_HASHTABLE) && isFullDebug(COMPONENT_RPCSEC_GSS)) 00211 LogFullDebug(COMPONENT_RPCSEC_GSS, 00212 "gss_ctx_hash_func : 0x%lx%lx --> %lx", 00213 (unsigned long)pgss_ctx->internal_ctx_id, 00214 (unsigned long)pgss_ctx->mech_type, 00215 hash_func ); 00216 00217 return hash_func % p_hparam->index_size; 00218 } /* gss_ctx_hash_func */ 00219 00236 uint64_t gss_ctx_rbt_hash_func(hash_parameter_t * p_hparam, hash_buffer_t * buffclef) 00237 { 00238 unsigned long hash_func; 00239 gss_union_ctx_id_desc *pgss_ctx; 00240 00241 pgss_ctx = (gss_union_ctx_id_desc *) (buffclef->pdata); 00242 00243 /* The gss context is basically made of two address in memory: one for the gss mech and one for the 00244 * mech's specific data for this context */ 00245 hash_func = 00246 (unsigned long)pgss_ctx->mech_type ^ (unsigned long)pgss_ctx->internal_ctx_id; 00247 00248 if(isFullDebug(COMPONENT_HASHTABLE) && isFullDebug(COMPONENT_RPCSEC_GSS)) 00249 LogFullDebug(COMPONENT_RPCSEC_GSS, 00250 "gss_ctx_rbt_hash_func : 0x%lx%lx --> %lx", 00251 (unsigned long)pgss_ctx->internal_ctx_id, 00252 (unsigned long)pgss_ctx->mech_type, 00253 hash_func ); 00254 00255 return hash_func; 00256 } /* gss_ctx_rbt_hash_func */ 00257 00271 int compare_gss_ctx(hash_buffer_t * buff1, hash_buffer_t * buff2) 00272 { 00273 gss_union_ctx_id_desc *pgss_ctx1 = (gss_union_ctx_id_desc *) (buff1->pdata); 00274 gss_union_ctx_id_desc *pgss_ctx2 = (gss_union_ctx_id_desc *) (buff2->pdata); 00275 00276 /* Check internal_ctx_id before mech_type before mech_type will VERY often be the same */ 00277 return ((pgss_ctx1->internal_ctx_id == pgss_ctx2->internal_ctx_id) 00278 && (pgss_ctx1->mech_type == pgss_ctx2->mech_type)) ? 0 : 1; 00279 } /* compare_gss_ctx */ 00280 00294 int display_gss_ctx(hash_buffer_t * pbuff, char *str) 00295 { 00296 gss_union_ctx_id_desc *pgss_ctx; 00297 00298 pgss_ctx = (gss_union_ctx_id_desc *) (pbuff->pdata); 00299 00300 return sprint_ctx(str, (unsigned char *)pgss_ctx, sizeof(*pgss_ctx)); 00301 } /* display_gss_ctx */ 00302 00317 int display_gss_svc_data(hash_buffer_t * pbuff, char *str) 00318 { 00319 struct svc_rpc_gss_data_stored *gd; 00320 00321 gd = (struct svc_rpc_gss_data_stored *)pbuff->pdata; 00322 00323 return sprintf(str, 00324 "established=%u ctx=(%lu) sec=(mech=%p,qop=%u,svc=%u,cred=%p,flags=%u) cname=(%lu|%s) seq=%u win=%u seqlast=%u seqmask=%u", 00325 gd->established, (long unsigned int)gd->ctx_exported.length, gd->sec.mech, gd->sec.qop, 00326 gd->sec.svc, gd->sec.cred, gd->sec.req_flags, (long unsigned int)gd->cname_len, 00327 gd->cname_val, gd->seq, gd->win, gd->seqlast, gd->seqmask); 00328 } /* display_gss_svc_data */ 00329 00339 int Gss_ctx_Hash_Set(gss_union_ctx_id_desc *pgss_ctx, struct svc_rpc_gss_data *gd) 00340 { 00341 hash_buffer_t buffkey; 00342 hash_buffer_t buffval; 00343 struct svc_rpc_gss_data_stored *stored_gd; 00344 char ctx_str[64]; 00345 const char *failure; 00346 00347 sprint_ctx(ctx_str, (char *)pgss_ctx, sizeof(*pgss_ctx)); 00348 00349 if((buffkey.pdata = gsh_malloc(sizeof(*pgss_ctx))) == NULL) 00350 { 00351 failure = "no memory for context"; 00352 goto fail; 00353 } 00354 00355 memcpy(buffkey.pdata, pgss_ctx, sizeof(*pgss_ctx)); 00356 buffkey.len = sizeof(*pgss_ctx); 00357 00358 if((buffval.pdata = 00359 gsh_malloc(sizeof(struct svc_rpc_gss_data_stored))) == NULL) 00360 { 00361 failure = "no memory for stored data"; 00362 goto fail; 00363 } 00364 00365 stored_gd = (struct svc_rpc_gss_data_stored *)buffval.pdata; 00366 00367 failure = gss_data2stored(gd, stored_gd); 00368 if(failure != NULL) 00369 goto fail; 00370 00371 00372 if(HashTable_Test_And_Set 00373 (ht_gss_ctx, &buffkey, &buffval, 00374 HASHTABLE_SET_HOW_SET_NO_OVERWRITE) != HASHTABLE_SUCCESS) 00375 { 00376 failure = "unable to set context"; 00377 goto fail; 00378 } 00379 00380 LogFullDebug(COMPONENT_RPCSEC_GSS, 00381 "Gss context %s added to hash", 00382 ctx_str); 00383 00384 return 1; 00385 00386 fail: 00387 LogCrit(COMPONENT_RPCSEC_GSS, 00388 "Gss context %s could not be added to hash because %s", 00389 ctx_str, failure); 00390 return 0; 00391 } /* Gss_ctx_Hash_Set */ 00392 00404 int Gss_ctx_Hash_Get(gss_union_ctx_id_desc *pgss_ctx, 00405 struct svc_rpc_gss_data *gd, 00406 bool_t **established, 00407 u_int **seqlast, 00408 uint32_t **seqmask) 00409 { 00410 hash_buffer_t buffkey; 00411 hash_buffer_t buffval; 00412 struct svc_rpc_gss_data_stored *stored_gd; 00413 char ctx_str[64]; 00414 const char *failure; 00415 00416 sprint_ctx(ctx_str, (char *)pgss_ctx, sizeof(*pgss_ctx)); 00417 00418 buffkey.pdata = (caddr_t) pgss_ctx; 00419 buffkey.len = sizeof(gss_union_ctx_id_desc); 00420 00421 if(HashTable_Get(ht_gss_ctx, &buffkey, &buffval) != HASHTABLE_SUCCESS) 00422 { 00423 LogCrit(COMPONENT_RPCSEC_GSS, 00424 "Gss context %s could not be found in hash", 00425 ctx_str); 00426 return 0; 00427 } 00428 00429 stored_gd = (struct svc_rpc_gss_data_stored *)buffval.pdata; 00430 failure = gss_stored2data(gd, stored_gd); 00431 if(failure != NULL) 00432 { 00433 LogCrit(COMPONENT_RPCSEC_GSS, 00434 "Gss context %s could not be recovered from hash because %s", 00435 ctx_str, failure); 00436 return 0; 00437 } 00438 00439 *established = &stored_gd->established; 00440 *seqlast = &stored_gd->seqlast; 00441 *seqmask = &stored_gd->seqmask; 00442 00443 return 1; 00444 } /* Gss_ctx_Hash_Get */ 00445 00455 int Gss_ctx_Hash_Del(gss_union_ctx_id_desc * pgss_ctx) 00456 { 00457 hash_buffer_t buffkey, old_key, old_value; 00458 00459 buffkey.pdata = (caddr_t) pgss_ctx; 00460 buffkey.len = sizeof(gss_union_ctx_id_desc); 00461 00462 if(HashTable_Del(ht_gss_ctx, &buffkey, &old_key, &old_value) == HASHTABLE_SUCCESS) 00463 { 00464 /* free the key that was stored in hash table */ 00465 gsh_free(old_key.pdata); 00466 gsh_free(old_value.pdata); 00467 00468 return 1; 00469 } 00470 else 00471 return 0; 00472 } /* Gss_ctx_Hash_Del */ 00473 00483 int Gss_ctx_Hash_Init(nfs_krb5_parameter_t param) 00484 { 00485 if((ht_gss_ctx = HashTable_Init(¶m.hash_param)) == NULL) 00486 { 00487 LogCrit(COMPONENT_RPCSEC_GSS, "GSS_CTX_HASH: Cannot init GSS CTX cache"); 00488 return -1; 00489 } 00490 00491 return 0; 00492 } /* Gss_ctx_Hash_Init */ 00493 00503 void Gss_ctx_Hash_Print(void) 00504 { 00505 HashTable_Log(COMPONENT_RPCSEC_GSS, ht_gss_ctx); 00506 } /* Gss_ctx_Hash_Print */