nfs-ganesha 1.4

AuthGss_HashTable.c

Go to the documentation of this file.
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(&param.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 */