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 "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