nfs-ganesha 1.4

nfs4_acls.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 "abstract_mem.h"
00010 #include "fsal.h"
00011 #include "HashTable.h"
00012 #include "log.h"
00013 #include "RW_Lock.h"
00014 #include "nfs4_acls.h"
00015 #include <openssl/md5.h>
00016 
00017 pool_t *fsal_acl_pool;
00018 static pthread_mutex_t fsal_acl_pool_mutex = PTHREAD_MUTEX_INITIALIZER;
00019 
00020 pool_t *fsal_acl_key_pool;
00021 static pthread_mutex_t fsal_acl_key_pool_mutex = PTHREAD_MUTEX_INITIALIZER;
00022 
00023 static int fsal_acl_hash_both(hash_parameter_t * p_hparam,
00024                               hash_buffer_t * buffclef,
00025                               uint32_t * phashval,
00026                               uint64_t * prbtval);
00027 static int compare_fsal_acl(hash_buffer_t * p_key1, hash_buffer_t * p_key2);
00028 static int display_fsal_acl_key(hash_buffer_t * p_val, char *outbuff);
00029 static int display_fsal_acl_val(hash_buffer_t * p_val, char *outbuff);
00030 
00031 /* DEFAULT PARAMETERS for hash table */
00032 
00033 static hash_parameter_t fsal_acl_hash_config = {
00034   .index_size = 67,
00035   .alphabet_length = 10,
00036   .hash_func_key = NULL,
00037   .hash_func_rbt = NULL,
00038   .hash_func_both = fsal_acl_hash_both,
00039   .compare_key = compare_fsal_acl,
00040   .key_to_str = display_fsal_acl_key,
00041   .val_to_str = display_fsal_acl_val,
00042   .ht_name = "ACL Table",
00043   .flags = HT_FLAG_CACHE,
00044   .ht_log_component = COMPONENT_NFS_V4_ACL
00045 };
00046 
00047 static hash_table_t *fsal_acl_hash = NULL;
00048 
00049 /* hash table functions */
00050 
00051 static int fsal_acl_hash_both(hash_parameter_t *p_hparam,
00052                               hash_buffer_t *buffclef,
00053                               uint32_t *phashval,
00054                               uint64_t *prbtval)
00055 {
00056   char printbuf[2 * MD5_DIGEST_LENGTH];
00057   uint32_t h1 = 0 ;
00058   uint32_t h2 = 0 ;
00059 
00060   char *p_aclkey = (buffclef->pdata);
00061 
00062   Lookup3_hash_buff_dual(p_aclkey, MD5_DIGEST_LENGTH, &h1, &h2);
00063 
00064   h1 = h1 % p_hparam->index_size;
00065 
00066   *phashval = h1 ;
00067   *prbtval = h2 ;
00068 
00069   if(isDebug(COMPONENT_NFS_V4_ACL))
00070     {
00071       snprintmem(printbuf, 2 * MD5_DIGEST_LENGTH, p_aclkey, MD5_DIGEST_LENGTH);
00072       LogDebug(COMPONENT_NFS_V4_ACL, "p_aclkey=%s, hashvalue=%u, rbtvalue=%u", printbuf, h1, h2);
00073     }
00074 
00075   /* Success */
00076   return 1 ;
00077 } /*  fsal_acl_hash_both */
00078 
00079 static int compare_fsal_acl(hash_buffer_t * p_key1, hash_buffer_t * p_key2)
00080 {
00081   return memcmp((char *)p_key1->pdata, (char *)p_key2->pdata, MD5_DIGEST_LENGTH);
00082 }
00083 
00084 static int display_fsal_acl_key(hash_buffer_t * p_val, char *outbuff)
00085 {
00086   char printbuf[2 * MD5_DIGEST_LENGTH];
00087   char *p_aclkey = (char *) p_val->pdata;
00088 
00089   snprintmem(printbuf, 2 * MD5_DIGEST_LENGTH, p_aclkey, MD5_DIGEST_LENGTH);
00090 
00091   return sprintf(outbuff, "%s", printbuf);
00092 }
00093 
00094 static int display_fsal_acl_val(hash_buffer_t * p_val, char *outbuff)
00095 {
00096   return sprintf(outbuff, "not implemented");
00097 }
00098 
00099 fsal_ace_t *nfs4_ace_alloc(int nace)
00100 {
00101   fsal_ace_t *pace = NULL;
00102 
00103   pace = gsh_calloc(nace, sizeof(fsal_ace_t));
00104   return pace;
00105 }
00106 
00107 static fsal_acl_t *nfs4_acl_alloc()
00108 {
00109   fsal_acl_t *pacl = NULL;
00110 
00111   pacl = pool_alloc(fsal_acl_pool, NULL);
00112 
00113   if(pacl == NULL)
00114   {
00115     LogCrit(COMPONENT_NFS_V4_ACL,
00116             "Can't allocate a new entry from fsal ACL pool");
00117     return NULL;
00118   }
00119 
00120   return pacl;
00121 }
00122 
00123 void nfs4_ace_free(fsal_ace_t *pace)
00124 {
00125   if(!pace)
00126     return;
00127 
00128   LogDebug(COMPONENT_NFS_V4_ACL,
00129            "free ace %p", pace);
00130 
00131   gsh_free(pace);
00132 }
00133 
00134 static void nfs4_acl_free(fsal_acl_t *pacl)
00135 {
00136   if(!pacl)
00137     return;
00138 
00139   if(pacl->aces)
00140     nfs4_ace_free(pacl->aces);
00141 
00142   P(fsal_acl_pool_mutex);
00143   pool_free(fsal_acl_pool, pacl);
00144   V(fsal_acl_pool_mutex);
00145  }
00146 
00147 static int nfs4_acldata_2_key(hash_buffer_t * pkey, fsal_acl_data_t *pacldata)
00148 {
00149   MD5_CTX c;
00150   fsal_acl_key_t *pacl_key = NULL;
00151 
00152   pacl_key = pool_alloc(fsal_acl_key_pool, NULL);
00153 
00154   if(pacl_key == NULL)
00155   {
00156     LogCrit(COMPONENT_NFS_V4_ACL,
00157             "Can't allocate a new entry from fsal ACL key pool");
00158     return NFS_V4_ACL_INTERNAL_ERROR;
00159   }
00160 
00161   MD5_Init(&c);
00162   MD5_Update(&c, (char *)pacldata->aces, pacldata->naces * sizeof(fsal_ace_t));
00163   MD5_Final(pacl_key->digest, &c);
00164 
00165   pkey->pdata = (caddr_t) pacl_key;
00166   pkey->len = sizeof(fsal_acl_key_t);
00167 
00168   return NFS_V4_ACL_SUCCESS;
00169 }
00170 
00171 static void nfs4_release_acldata_key(hash_buffer_t *pkey)
00172 {
00173   fsal_acl_key_t *pacl_key = NULL;
00174 
00175   if(!pkey)
00176     return;
00177 
00178   pacl_key = (fsal_acl_key_t *)pkey->pdata;
00179 
00180   if(!pacl_key)
00181     return;
00182 
00183   P(fsal_acl_key_pool_mutex);
00184   pool_free(fsal_acl_key_pool, pacl_key);
00185   V(fsal_acl_key_pool_mutex);
00186  }
00187 
00188 void nfs4_acl_entry_inc_ref(fsal_acl_t *pacl)
00189 {
00190   /* Increase ref counter */
00191   P_w(&pacl->lock);
00192   pacl->ref++;
00193   LogDebug(COMPONENT_NFS_V4_ACL,
00194            "(acl, ref) = (%p, %u)",
00195            pacl, pacl->ref);
00196   V_w(&pacl->lock);
00197 }
00198 
00199 /* Should be called with lock held. */
00200 static void nfs4_acl_entry_dec_ref(fsal_acl_t *pacl)
00201 {
00202   /* Decrease ref counter */
00203   pacl->ref--;
00204   LogDebug(COMPONENT_NFS_V4_ACL,
00205            "(acl, ref) = (%p, %u)",
00206            pacl, pacl->ref);
00207 }
00208 
00209 fsal_acl_t *nfs4_acl_new_entry(fsal_acl_data_t *pacldata, fsal_acl_status_t *pstatus)
00210 {
00211   fsal_acl_t        * pacl = NULL;
00212   hash_buffer_t       buffkey;
00213   hash_buffer_t       buffvalue;
00214   int                 rc;
00215   struct hash_latch   latch;
00216 
00217   /* Set the return default to NFS_V4_ACL_SUCCESS */
00218   *pstatus = NFS_V4_ACL_SUCCESS;
00219 
00220   LogDebug(COMPONENT_NFS_V4_ACL,
00221            "ACL hash table size=%zu",
00222            HashTable_GetSize(fsal_acl_hash));
00223 
00224   /* Turn the input to a hash key */
00225   if(nfs4_acldata_2_key(&buffkey, pacldata))
00226     {
00227       *pstatus = NFS_V4_ACL_UNAPPROPRIATED_KEY;
00228 
00229       nfs4_release_acldata_key(&buffkey);
00230 
00231       nfs4_ace_free(pacldata->aces);
00232 
00233       return NULL;
00234     }
00235 
00236   /* Check if the entry already exists */
00237   rc =  HashTable_GetLatch(fsal_acl_hash,
00238                            &buffkey,
00239                            &buffvalue,
00240                            TRUE,
00241                            &latch);
00242   if(rc == HASHTABLE_SUCCESS)
00243     {
00244       /* Entry is already in the cache, do not add it */
00245       pacl = (fsal_acl_t *) buffvalue.pdata;
00246       *pstatus = NFS_V4_ACL_EXISTS;
00247 
00248       nfs4_release_acldata_key(&buffkey);
00249 
00250       nfs4_ace_free(pacldata->aces);
00251 
00252       nfs4_acl_entry_inc_ref(pacl);
00253 
00254       HashTable_ReleaseLatched(fsal_acl_hash, &latch);
00255 
00256       return pacl;
00257     }
00258 
00259   /* Any other result other than no such key is an error */
00260   if(rc != HASHTABLE_ERROR_NO_SUCH_KEY)
00261     {
00262       *pstatus = NFS_V4_ACL_INIT_ENTRY_FAILED;
00263 
00264       nfs4_release_acldata_key(&buffkey);
00265 
00266       nfs4_ace_free(pacldata->aces);
00267 
00268       return NULL;
00269     }
00270 
00271   /* Adding the entry in the cache */
00272   pacl = nfs4_acl_alloc();
00273   if(rw_lock_init(&(pacl->lock)) != 0)
00274     {
00275       nfs4_acl_free(pacl);
00276       LogCrit(COMPONENT_NFS_V4_ACL,
00277               "New ACL rw_lock_init returned %d (%s)",
00278               errno, strerror(errno));
00279       *pstatus = NFS_V4_ACL_INIT_ENTRY_FAILED;
00280 
00281       nfs4_release_acldata_key(&buffkey);
00282 
00283       nfs4_ace_free(pacldata->aces);
00284 
00285       HashTable_ReleaseLatched(fsal_acl_hash, &latch);
00286 
00287       return NULL;
00288     }
00289 
00290   pacl->naces = pacldata->naces;
00291   pacl->aces  = pacldata->aces;
00292   pacl->ref   = 1;               /* We give out one reference */
00293 
00294   /* Build the value */
00295   buffvalue.pdata = (caddr_t) pacl;
00296   buffvalue.len = sizeof(fsal_acl_t);
00297 
00298   rc = HashTable_SetLatched(fsal_acl_hash,
00299                             &buffkey,
00300                             &buffvalue,
00301                             &latch,
00302                             HASHTABLE_SET_HOW_SET_NO_OVERWRITE,
00303                             NULL,
00304                             NULL);
00305 
00306   if(rc != HASHTABLE_SUCCESS)
00307     {
00308       /* Put the entry back in its pool */
00309       nfs4_acl_free(pacl);
00310       LogWarn(COMPONENT_NFS_V4_ACL,
00311               "New ACL entry could not be added to hash, rc=%s",
00312               hash_table_err_to_str(rc));
00313 
00314       *pstatus = NFS_V4_ACL_HASH_SET_ERROR;
00315 
00316       nfs4_release_acldata_key(&buffkey);
00317 
00318       return NULL;
00319     }
00320 
00321   return pacl;
00322 }
00323 
00324 void nfs4_acl_release_entry(fsal_acl_t *pacl, fsal_acl_status_t *pstatus)
00325 {
00326   fsal_acl_data_t   acldata;
00327   hash_buffer_t     key, old_key;
00328   hash_buffer_t     old_value;
00329   int               rc;
00330   struct hash_latch latch;
00331 
00332   /* Set the return default to NFS_V4_ACL_SUCCESS */
00333   *pstatus = NFS_V4_ACL_SUCCESS;
00334 
00335   if (pacl == NULL)
00336     return;
00337 
00338   P_w(&pacl->lock);
00339   if(pacl->ref > 1)
00340     {
00341       nfs4_acl_entry_dec_ref(pacl);
00342       V_w(&pacl->lock);
00343       return;
00344     }
00345   else
00346       LogDebug(COMPONENT_NFS_V4_ACL, "Free ACL %p", pacl);
00347 
00348   /* Turn the input to a hash key */
00349   acldata.naces = pacl->naces;
00350   acldata.aces = pacl->aces;
00351 
00352   if(nfs4_acldata_2_key(&key, &acldata))
00353   {
00354     *pstatus = NFS_V4_ACL_UNAPPROPRIATED_KEY;
00355 
00356     nfs4_release_acldata_key(&key);
00357 
00358     V_w(&pacl->lock);
00359 
00360     return;
00361   }
00362 
00363   V_w(&pacl->lock);
00364 
00365   /* Get the hash table entry and hold latch */
00366   rc = HashTable_GetLatch(fsal_acl_hash,
00367                           &key,
00368                           &old_value,
00369                           TRUE,
00370                           &latch);
00371 
00372   switch(rc)
00373     {
00374       case HASHTABLE_ERROR_NO_SUCH_KEY:
00375         HashTable_ReleaseLatched(fsal_acl_hash, &latch);
00376         return;
00377 
00378       case HASHTABLE_SUCCESS:
00379         P_w(&pacl->lock);
00380         nfs4_acl_entry_dec_ref(pacl);
00381         if(pacl->ref != 0)
00382           {
00383             /* Did not actually release last reference */
00384             HashTable_ReleaseLatched(fsal_acl_hash, &latch);
00385             V_w(&pacl->lock);
00386             return;
00387           }
00388 
00389         /* use the key to delete the entry */
00390         rc = HashTable_DeleteLatched(fsal_acl_hash,
00391                                      &key,
00392                                      &latch,
00393                                      &old_key,
00394                                      &old_value);
00395         if(rc == HASHTABLE_SUCCESS)
00396            break;
00397 
00398          /* Fall through to default case */
00399 
00400       default:
00401           LogCrit(COMPONENT_NFS_V4_ACL,
00402                   "ACL entry could not be deleted, status=%s",
00403                   hash_table_err_to_str(rc));
00404           return;
00405     }
00406 
00407   /* Release the hash key data */
00408   nfs4_release_acldata_key(&old_key);
00409 
00410   /* Sanity check: old_value.pdata is expected to be equal to pacl,
00411    * and is released later in this function */
00412   if((fsal_acl_t *) old_value.pdata != pacl)
00413     {
00414       LogCrit(COMPONENT_NFS_V4_ACL,
00415               "Unexpected ACL %p from hash table (pacl=%p)",
00416               old_value.pdata, pacl);
00417     }
00418 
00419   /* Release the current key */
00420   nfs4_release_acldata_key(&key);
00421 
00422   V_w(&pacl->lock);
00423 
00424   /* Release acl */
00425   nfs4_acl_free(pacl);
00426 }
00427 
00428 static void nfs4_acls_test()
00429 {
00430   int i = 0;
00431   fsal_acl_data_t acldata, acldata2;
00432   fsal_ace_t *pace = NULL;
00433   fsal_acl_t *pacl = NULL;
00434   fsal_acl_status_t status;
00435 
00436   acldata.naces = 3;
00437   acldata.aces = nfs4_ace_alloc(3);
00438   LogDebug(COMPONENT_NFS_V4_ACL, "acldata.aces = %p", acldata.aces);
00439 
00440   pace = acldata.aces;
00441 
00442   for(i = 0; i < 3; i++)
00443     {
00444       pace->type = i;
00445       pace->perm = i;
00446       pace->flag = i;
00447       pace->who.uid = i;
00448       pace++;
00449     }
00450 
00451   pacl = nfs4_acl_new_entry(&acldata, &status);
00452   P_r(&pacl->lock);
00453   LogDebug(COMPONENT_NFS_V4_ACL, "pacl = %p, ref = %u, status = %u", pacl, pacl->ref, status);
00454   V_r(&pacl->lock);
00455 
00456   acldata2.naces = 3;
00457   acldata2.aces = nfs4_ace_alloc(3);
00458 
00459   LogDebug(COMPONENT_NFS_V4_ACL, "acldata2.aces = %p", acldata2.aces);
00460 
00461   pace = acldata2.aces;
00462 
00463   for(i = 0; i < 3; i++)
00464     {
00465       pace->type = i;
00466       pace->perm = i;
00467       pace->flag = i;
00468       pace->who.uid = i;
00469       pace++;
00470     }
00471 
00472   pacl = nfs4_acl_new_entry(&acldata2, &status);
00473   P_r(&pacl->lock);
00474   LogDebug(COMPONENT_NFS_V4_ACL, "re-access: pacl = %p, ref = %u, status = %u", pacl, pacl->ref, status);
00475   V_r(&pacl->lock);
00476 
00477   nfs4_acl_release_entry(pacl, &status);
00478   P_r(&pacl->lock);
00479   LogDebug(COMPONENT_NFS_V4_ACL, "release: pacl = %p, ref = %u, status = %u", pacl, pacl->ref, status);
00480   V_r(&pacl->lock);
00481 
00482   nfs4_acl_release_entry(pacl, &status);
00483 }
00484 
00485 int nfs4_acls_init()
00486 {
00487   LogDebug(COMPONENT_NFS_V4_ACL, "Initialize NFSv4 ACLs");
00488   LogDebug(COMPONENT_NFS_V4_ACL,
00489            "sizeof(fsal_ace_t)=%zu, sizeof(fsal_acl_t)=%zu",
00490            sizeof(fsal_ace_t), sizeof(fsal_acl_t));
00491 
00492   /* Initialize memory pool of ACLs. */
00493   fsal_acl_pool = pool_init(NULL, sizeof(fsal_acl_t),
00494                             pool_basic_substrate,
00495                             NULL, NULL, NULL);
00496 
00497   /* Initialize memory pool of ACL keys. */
00498   fsal_acl_key_pool = pool_init(NULL, sizeof(fsal_acl_key_t),
00499                                 pool_basic_substrate,
00500                                 NULL, NULL, NULL);
00501 
00502   /* Create hash table. */
00503   fsal_acl_hash = HashTable_Init(&fsal_acl_hash_config);
00504 
00505   if(!fsal_acl_hash)
00506     {
00507       LogCrit(COMPONENT_NFS_V4_ACL, "ERROR creating hash table for NFSv4 ACLs");
00508       return NFS_V4_ACL_INTERNAL_ERROR;
00509     }
00510 
00511   nfs4_acls_test();
00512 
00513   return NFS_V4_ACL_SUCCESS;
00514 }
00515