summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShreyas Siravara <sshreyas@fb.com>2015-03-25 12:50:11 -0700
committerJeff Darcy <jeff@pl.atyp.us>2017-08-29 15:11:10 +0000
commit1f7b0cb7e81eb1c12b527138c0c64f8d4e093426 (patch)
tree0ac8fccdba57c060dc8e3b846d7611ae6fce0255
parent9255f94bc29990e7d08ad5189ba9c3bda2ccba9a (diff)
Add negative caching to nfs auth cache
Summary: This diff adds the ability to the nfs daemon to cache hosts it has deauthorized for mounts, not just the hosts it has authorized. This allows a host that has been denied to be deauthorized for ttl # of seconds, or until the nfs daemon has restarted. Test Plan: Use the prove tests to maintain the integrity of the auth code. Test manually to see if the correct code path is being hit. Reviewers: dph, rwareing Reviewed By: rwareing Differential Revision: https://phabricator.fb.com/D1947728 Change-Id: I9728e15913e0900ab34311b13b30eba0b91ce33f Reviewed-on: https://review.gluster.org/18134 Smoke: Gluster Build System <jenkins@build.gluster.org> Reviewed-by: Jeff Darcy <jeff@pl.atyp.us> Tested-by: Jeff Darcy <jeff@pl.atyp.us> CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
-rw-r--r--xlators/debug/io-stats/src/io-stats.c2
-rw-r--r--xlators/nfs/server/src/auth-cache.c542
-rw-r--r--xlators/nfs/server/src/auth-cache.h31
-rw-r--r--xlators/nfs/server/src/exports.h9
-rw-r--r--xlators/nfs/server/src/mount3.c56
5 files changed, 289 insertions, 351 deletions
diff --git a/xlators/debug/io-stats/src/io-stats.c b/xlators/debug/io-stats/src/io-stats.c
index 69f182c5194..b02819f1013 100644
--- a/xlators/debug/io-stats/src/io-stats.c
+++ b/xlators/debug/io-stats/src/io-stats.c
@@ -726,7 +726,7 @@ ios_stats_cleanup (xlator_t *this, inode_t *inode)
fprintf (logfp, fmt); \
fprintf (logfp, "\n"); \
} \
- gf_log (this->name, GF_LOG_DEBUG, fmt); \
+ gf_log (this->name, GF_LOG_TRACE, fmt); \
} while (0)
int
diff --git a/xlators/nfs/server/src/auth-cache.c b/xlators/nfs/server/src/auth-cache.c
index 730e0a97d20..a607502c9de 100644
--- a/xlators/nfs/server/src/auth-cache.c
+++ b/xlators/nfs/server/src/auth-cache.c
@@ -17,47 +17,28 @@
#include "exports.h"
#include "nfs-messages.h"
-enum auth_cache_lookup_results {
- ENTRY_FOUND = 0,
- ENTRY_NOT_FOUND = -1,
- ENTRY_EXPIRED = -2,
-};
-
-struct auth_cache_entry {
- GF_REF_DECL; /* refcounting */
- data_t *data; /* data_unref() on refcount == 0 */
-
- time_t timestamp;
- struct export_item *item;
-};
-
/* Given a filehandle and an ip, creates a colon delimited hashkey.
*/
-static char*
-make_hashkey(struct nfs3_fh *fh, const char *host)
-{
- char *hashkey = NULL;
- char exportid[256] = {0, };
- char gfid[256] = {0, };
- char mountid[256] = {0, };
- size_t nbytes = 0;
-
- gf_uuid_unparse (fh->exportid, exportid);
- gf_uuid_unparse (fh->gfid, gfid);
- gf_uuid_unparse (fh->mountid, mountid);
-
- nbytes = strlen (exportid) + strlen (host)
- + strlen (mountid) + 3;
- hashkey = GF_MALLOC (nbytes, gf_common_mt_char);
- if (!hashkey)
- return NULL;
-
- snprintf (hashkey, nbytes, "%s:%s:%s", exportid,
- mountid, host);
-
- return hashkey;
-}
-
+#define make_fh_hashkey(hashkey, fh, host) \
+ do { \
+ char exportid[256] = {0, }; \
+ char mountid[256] = {0, }; \
+ size_t nbytes = 0; \
+ gf_uuid_unparse (fh->exportid, exportid); \
+ gf_uuid_unparse (fh->mountid, mountid); \
+ nbytes = strlen (exportid) + strlen (host) \
+ + strlen (mountid) + 5; \
+ hashkey = alloca (nbytes); \
+ snprintf (hashkey, nbytes, "%s:%s:%s", exportid, \
+ mountid, host); \
+ } while (0); \
+
+#define make_path_hashkey(hashkey, path, host) \
+ do { \
+ size_t nbytes = strlen (path) + strlen (host) + 2; \
+ hashkey = alloca (nbytes); \
+ snprintf (hashkey, nbytes, "%s:%s", path, host); \
+ } while (0);
/**
* auth_cache_init -- Initialize an auth cache and set the ttl_sec
*
@@ -86,28 +67,11 @@ out:
return cache;
}
-/* auth_cache_entry_free -- called by refcounting subsystem on refcount == 0
- *
- * @to_free: auth_cache_entry that has refcount == 0 and needs to get free'd
- */
-void
-auth_cache_entry_free (void *to_free)
-{
- struct auth_cache_entry *entry = to_free;
- data_t *entry_data = NULL;
-
- GF_VALIDATE_OR_GOTO (GF_NFS, entry, out);
- GF_VALIDATE_OR_GOTO (GF_NFS, entry->data, out);
-
- entry_data = entry->data;
- /* set data_t->data to NULL, otherwise data_unref() tries to free it */
- entry_data->data = NULL;
- data_unref (entry_data);
-
- GF_FREE (entry);
-out:
- return;
-}
+struct auth_cache_entry {
+ time_t timestamp;
+ struct export_item *item;
+ gf_boolean_t access_allowed;
+};
/**
* auth_cache_entry_init -- Initialize an auth cache entry
@@ -124,303 +88,203 @@ auth_cache_entry_init ()
if (!entry)
gf_msg (GF_NFS, GF_LOG_WARNING, ENOMEM, NFS_MSG_NO_MEMORY,
"failed to allocate entry");
- else
- GF_REF_INIT (entry, auth_cache_entry_free);
return entry;
}
+// Internal lookup
+enum _internal_cache_lookup_results {
+ ENTRY_NOT_FOUND = -1,
+ ENTRY_EXPIRED = -2,
+};
+
/**
- * auth_cache_add -- Add an auth_cache_entry to the cache->dict
+ * auth_cache_purge -- Purge the dict in the cache and set
+ * the dict pointer to NULL. It will be allocated
+ * on the first insert into the dict.
+ *
+ * @cache: Cache to purge
*
- * @return: 0 on success, non-zero otherwise.
*/
-static int
-auth_cache_add (struct auth_cache *cache, char *hashkey,
- struct auth_cache_entry *entry)
+void
+auth_cache_purge (struct auth_cache *cache)
{
- int ret = -1;
- data_t *entry_data = NULL;
-
- GF_VALIDATE_OR_GOTO (GF_NFS, cache, out);
- GF_VALIDATE_OR_GOTO (GF_NFS, cache->cache_dict, out);
-
- ret = GF_REF_GET (entry);
- if (ret == 0) {
- /* entry does not have any references */
- ret = -1;
- goto out;
- }
+ dict_t *new_cache_dict = NULL;
+ dict_t *old_cache_dict = cache->cache_dict;
- entry_data = bin_to_data (entry, sizeof (*entry));
- if (!entry_data) {
- ret = -1;
- GF_REF_PUT (entry);
+ if (!cache || !cache->cache_dict)
goto out;
- }
- /* we'll take an extra ref on the data_t, it gets unref'd when the
- * auth_cache_entry is released */
- entry->data = data_ref (entry_data);
+ (void)__sync_lock_test_and_set (&cache->cache_dict, new_cache_dict);
- LOCK (&cache->lock);
- {
- ret = dict_set (cache->cache_dict, hashkey, entry_data);
- }
- UNLOCK (&cache->lock);
-
- if (ret) {
- /* adding to dict failed */
- GF_REF_PUT (entry);
- }
+ dict_destroy (old_cache_dict);
out:
- return ret;
+ return;
}
-/**
- * _auth_cache_expired -- Check if the auth_cache_entry has expired
- *
- * The auth_cache->lock should have been taken when this function is called.
- *
- * @return: true when the auth_cache_entry is expired, false otherwise.
- */
-static int
-_auth_cache_expired (struct auth_cache *cache, struct auth_cache_entry *entry)
-{
- return ((time (NULL) - entry->timestamp) > cache->ttl_sec);
-}
/**
- * auth_cache_get -- Get the @hashkey entry from the cache->cache_dict
- *
- * @cache: The auth_cache that should contain the @entry.
- * @haskkey: The key associated with the auth_cache_entry.
- * @entry: The found auth_cache_entry, unmodified if not found/expired.
- *
- * The using the cache->dict requires locking, this function takes care of
- * that. When the entry is found, but has expired, it will be removed from the
- * cache_dict.
- *
- * @return: 0 when found, ENTRY_NOT_FOUND or ENTRY_EXPIRED otherwise.
+ * Lookup filehandle or path from the cache.
*/
-static enum auth_cache_lookup_results
-auth_cache_get (struct auth_cache *cache, char *hashkey,
- struct auth_cache_entry **entry)
+int _cache_lookup (struct auth_cache *cache, char *key,
+ struct auth_cache_entry **entry)
{
- enum auth_cache_lookup_results ret = ENTRY_NOT_FOUND;
- data_t *entry_data = NULL;
- struct auth_cache_entry *lookup_res = NULL;
+ int ret = ENTRY_NOT_FOUND;
+ struct auth_cache_entry *lookup_res;
+ data_t *entry_data;
- GF_VALIDATE_OR_GOTO (GF_NFS, cache, out);
- GF_VALIDATE_OR_GOTO (GF_NFS, cache->cache_dict, out);
- GF_VALIDATE_OR_GOTO (GF_NFS, hashkey, out);
-
- LOCK (&cache->lock);
- {
- entry_data = dict_get (cache->cache_dict, hashkey);
- if (!entry_data)
- goto unlock;
-
- lookup_res = (struct auth_cache_entry *)(entry_data->data);
- if (GF_REF_GET (lookup_res) == 0) {
- /* entry has been free'd */
- ret = ENTRY_EXPIRED;
- goto unlock;
- }
+ if (!cache->cache_dict) {
+ goto out;
+ }
- if (_auth_cache_expired (cache, lookup_res)) {
- ret = ENTRY_EXPIRED;
+ if (!entry) {
+ goto out;
+ }
- /* free entry and remove from the cache */
- GF_FREE (lookup_res);
- entry_data->data = NULL;
- dict_del (cache->cache_dict, hashkey);
+ *entry = NULL;
- goto unlock;
- }
+ entry_data = dict_get (cache->cache_dict, key);
+ if (!entry_data) {
+ goto out;
+ }
- *entry = lookup_res;
- ret = ENTRY_FOUND;
+ lookup_res = (struct auth_cache_entry *)(entry_data->data);
+ if (time (NULL) - lookup_res->timestamp > cache->ttl_sec) {
+ GF_FREE (lookup_res);
+ entry_data->data = NULL;
+ dict_del (cache->cache_dict, key); // Remove from the cache
+ ret = ENTRY_EXPIRED;
+ goto out;
}
-unlock:
- UNLOCK (&cache->lock);
+
+ *entry = lookup_res;
+
+ return 0;
out:
- return ret;
+ return -1;
}
/**
- * auth_cache_lookup -- Lookup an item from the cache
- *
- * @cache: cache to lookup from
- * @fh : FH to use in lookup
- * @host_addr: Address to use in lookup
- * @timestamp: The timestamp to set when lookup succeeds
- * @can_write: Is the host authorized to write to the filehandle?
- *
- * If the current time - entry time of the cache entry > ttl_sec,
- * we remove the element from the dict and return ENTRY_EXPIRED.
- *
- * @return: ENTRY_EXPIRED if entry expired
- * ENTRY_NOT_FOUND if entry not found in dict
- * 0 if found
+ * Lookup filehandle from the cache.
*/
-enum auth_cache_lookup_results
-auth_cache_lookup (struct auth_cache *cache, struct nfs3_fh *fh,
- const char *host_addr, time_t *timestamp,
- gf_boolean_t *can_write)
+int
+_cache_lookup_fh (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr, struct auth_cache_entry **ec)
{
- char *hashkey = NULL;
- struct auth_cache_entry *lookup_res = NULL;
- enum auth_cache_lookup_results ret = ENTRY_NOT_FOUND;
-
- GF_VALIDATE_OR_GOTO (GF_NFS, cache, out);
- GF_VALIDATE_OR_GOTO (GF_NFS, fh, out);
- GF_VALIDATE_OR_GOTO (GF_NFS, host_addr, out);
- GF_VALIDATE_OR_GOTO (GF_NFS, timestamp, out);
- GF_VALIDATE_OR_GOTO (GF_NFS, can_write, out);
-
- hashkey = make_hashkey (fh, host_addr);
- if (!hashkey) {
- ret = -ENOMEM;
- goto out;
+ char *hashkey;
+ int ret = ENTRY_NOT_FOUND;
+ if (fh && host_addr) {
+ make_fh_hashkey (hashkey, fh, host_addr);
+ ret =_cache_lookup (cache, hashkey, ec);
}
-
- ret = auth_cache_get (cache, hashkey, &lookup_res);
- switch (ret) {
- case ENTRY_FOUND:
- *timestamp = lookup_res->timestamp;
- *can_write = lookup_res->item->opts->rw;
- GF_REF_PUT (lookup_res);
- break;
-
- case ENTRY_NOT_FOUND:
- gf_msg_debug (GF_NFS, 0, "could not find entry for %s",
- host_addr);
- break;
-
- case ENTRY_EXPIRED:
- gf_msg_debug (GF_NFS, 0, "entry for host %s has expired",
- host_addr);
- break;
- }
-
-out:
- GF_FREE (hashkey);
-
return ret;
}
-/* auth_cache_entry_purge -- free up the auth_cache_entry
- *
- * This gets called through dict_foreach() by auth_cache_purge(). Each
- * auth_cache_entry has a refcount which needs to be decremented. Once the
- * auth_cache_entry reaches refcount == 0, auth_cache_entry_free() will call
- * data_unref() to free the associated data_t.
- *
- * @d: dict that gets purged by auth_cache_purge()
- * @k: hashkey of the current entry
- * @v: data_t of the current entry
+/**
+ * Lookup path from the cache.
*/
int
-auth_cache_entry_purge (dict_t *d, char *k, data_t *v, void *_unused)
+_cache_lookup_path (struct auth_cache *cache, const char *path,
+ const char *host_addr, struct auth_cache_entry **ec)
{
- struct auth_cache_entry *entry = (struct auth_cache_entry *) v->data;
-
- if (entry)
- GF_REF_PUT (entry);
-
- return 0;
+ char *hashkey;
+ int ret = ENTRY_NOT_FOUND;
+ if (path && host_addr) {
+ make_path_hashkey (hashkey, path, host_addr);
+ ret = _cache_lookup (cache, hashkey, ec);
+ }
+ return ret;
}
/**
- * auth_cache_purge -- Purge the dict in the cache and create a new empty one.
- *
- * @cache: Cache to purge
- *
+ * cache_item -- Caches either a filehandle or path.
+ * See descriptions of functions that invoke this one.
*/
-void
-auth_cache_purge (struct auth_cache *cache)
+int
+cache_item (struct auth_cache *cache, const char *path, struct nfs3_fh *fh,
+ const char *host_addr, struct export_item *export_item,
+ auth_cache_status_t status)
{
- dict_t *new_cache_dict = dict_new ();
- dict_t *old_cache_dict = NULL;
+ int ret = -EINVAL;
+ data_t *entry_data = NULL;
+ struct auth_cache_entry *entry = NULL;
+ char *hashkey = NULL;
- if (!cache || !new_cache_dict)
+ GF_VALIDATE_OR_GOTO (GF_NFS, host_addr, out);
+ GF_VALIDATE_OR_GOTO (GF_NFS, cache, out);
+
+ // We can cache either a file-handle or a path, not both,
+ // and at least one of them must be defined!
+ if ((fh && path) || (!fh && !path)) {
goto out;
+ }
- LOCK (&cache->lock);
- {
- old_cache_dict = cache->cache_dict;
- cache->cache_dict = new_cache_dict;
+ // If a dict has not been allocated already, allocate it.
+ if (!cache->cache_dict) {
+ cache->cache_dict = dict_new ();
+ if (!cache->cache_dict) {
+ ret = -ENOMEM;
+ goto out;
+ }
}
- UNLOCK (&cache->lock);
- /* walk all entries and refcount-- with GF_REF_PUT() */
- dict_foreach (old_cache_dict, auth_cache_entry_purge, NULL);
- dict_unref (old_cache_dict);
-out:
- return;
-}
-/**
- * is_nfs_fh_cached_and_writeable -- Checks if an NFS FH is cached for the given
- * host
- * @cache: The fh cache
- * @host_addr: Address to use in lookup
- * @fh: The fh to use in lookup
- *
- *
- * @return: TRUE if cached, FALSE otherwise
- *
- */
-gf_boolean_t
-is_nfs_fh_cached (struct auth_cache *cache, struct nfs3_fh *fh,
- const char *host_addr)
-{
- int ret = 0;
- time_t timestamp = 0;
- gf_boolean_t cached = _gf_false;
- gf_boolean_t can_write = _gf_false;
+ // Find an entry with the filehandle or path, depending
+ // on which one is defined. Validation for these parameters
+ // is above.
+ if (fh) {
+ ret = _cache_lookup_fh (cache, fh, host_addr, &entry);
+ make_fh_hashkey (hashkey, fh, host_addr)
+ }
- if (!fh)
- goto out;
+ if (path) {
+ ret = _cache_lookup_path (cache, path, host_addr, &entry);
+ make_path_hashkey (hashkey, path, host_addr)
+ }
+
+ // If no entry was found, we need to create one.
+ if (!entry) {
+ entry = auth_cache_entry_init ();
+ GF_CHECK_ALLOC (entry, ret, out);
+ }
- ret = auth_cache_lookup (cache, fh, host_addr, &timestamp, &can_write);
- cached = (ret == ENTRY_FOUND);
+ // Populate the entry
+ entry->timestamp = time (NULL);
+ entry->item = export_item;
+ // Access is only allowed if the status is set to
+ // AUTH_CACHE_HOST_AUTH_OK
+ entry->access_allowed = (status == AUTH_CACHE_HOST_AUTH_OK);
+ // Put the entry into the cache
+ entry_data = bin_to_data (entry, sizeof (*entry));
+ dict_set (cache->cache_dict, hashkey, entry_data);
+ gf_log (GF_NFS, GF_LOG_TRACE, "Caching %s for host(%s) as %s",
+ path ? path : "fh", host_addr, entry->access_allowed ?
+ "ALLOWED" : "NOT ALLOWED");
out:
- return cached;
+ return ret;
}
-
/**
- * is_nfs_fh_cached_and_writeable -- Checks if an NFS FH is cached for the given
- * host and writable
- * @cache: The fh cache
- * @host_addr: Address to use in lookup
- * @fh: The fh to use in lookup
- *
+ * cache_nfs_path -- Places the path in the underlying dict as we are
+ * using as our cache. The value is an entry struct
+ * containing the export item that was authorized or
+ * deauthorized for the operation and the path authorized
+ * or deauthorized.
*
- * @return: TRUE if cached & writable, FALSE otherwise
+ * @cache: The cache to place fh's in
+ * @path : The path to cache
+ * @host_addr: The address of the host
+ * @export_item: The export item that was authorized/deauthorized
*
*/
-gf_boolean_t
-is_nfs_fh_cached_and_writeable (struct auth_cache *cache, struct nfs3_fh *fh,
- const char *host_addr)
+int
+cache_nfs_path (struct auth_cache *cache, const char *path,
+ const char *host_addr, struct export_item *export_item,
+ auth_cache_status_t status)
{
- int ret = 0;
- time_t timestamp = 0;
- gf_boolean_t cached = _gf_false;
- gf_boolean_t writable = _gf_false;
-
- if (!fh)
- goto out;
-
- ret = auth_cache_lookup (cache, fh, host_addr, &timestamp, &writable);
- cached = ((ret == ENTRY_FOUND) && writable);
-
-out:
- return cached;
+ return cache_item (cache, path, NULL, host_addr, export_item, status);
}
/**
@@ -438,52 +302,68 @@ out:
*/
int
cache_nfs_fh (struct auth_cache *cache, struct nfs3_fh *fh,
- const char *host_addr, struct export_item *export_item)
+ const char *host_addr, struct export_item *export_item,
+ auth_cache_status_t status)
{
- int ret = -EINVAL;
- char *hashkey = NULL;
- data_t *entry_data = NULL;
- time_t timestamp = 0;
- gf_boolean_t can_write = _gf_false;
- struct auth_cache_entry *entry = NULL;
+ return cache_item (cache, NULL, fh, host_addr, export_item, status);
+}
- GF_VALIDATE_OR_GOTO (GF_NFS, host_addr, out);
- GF_VALIDATE_OR_GOTO (GF_NFS, cache, out);
- GF_VALIDATE_OR_GOTO (GF_NFS, fh, out);
+auth_cache_status_t
+auth_cache_allows (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *path, const char *host_addr,
+ gf_boolean_t check_rw_access)
+{
+ int ret = 0;
+ int status = AUTH_CACHE_HOST_EACCES;
+ gf_boolean_t cache_allows = FALSE;
+ struct auth_cache_entry *ace = NULL;
- /* If we could already find it in the cache, just return */
- ret = auth_cache_lookup (cache, fh, host_addr, &timestamp, &can_write);
- if (ret == 0) {
- gf_msg_trace (GF_NFS, 0, "found cached auth/fh for host "
- "%s", host_addr);
+ if ((fh && path) || (!fh && !path)) {
+ status = AUTH_CACHE_HOST_ENOENT;
goto out;
}
- hashkey = make_hashkey (fh, host_addr);
- if (!hashkey) {
- ret = -ENOMEM;
- goto out;
+ if (fh) {
+ ret = _cache_lookup_fh (cache, fh, host_addr, &ace);
}
- entry = auth_cache_entry_init ();
- if (!entry) {
- ret = -ENOMEM;
- goto out;
+ if (path) {
+ ret = _cache_lookup_path (cache, path, host_addr, &ace);
}
- entry->timestamp = time (NULL);
- entry->item = export_item;
-
- ret = auth_cache_add (cache, hashkey, entry);
- GF_REF_PUT (entry);
- if (ret)
- goto out;
+ cache_allows = (ret == 0) && ace->access_allowed;
+ if (check_rw_access) {
+ cache_allows = cache_allows && ace->item->opts->rw;
+ }
- gf_msg_trace (GF_NFS, 0, "Caching file-handle (%s)", host_addr);
- ret = 0;
+ if (!ace) {
+ status = AUTH_CACHE_HOST_ENOENT;
+ }
+ if (cache_allows) {
+ status = AUTH_CACHE_HOST_AUTH_OK;
+ }
out:
- GF_FREE (hashkey);
+ return status;
+}
- return ret;
+auth_cache_status_t
+auth_cache_allows_fh (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr)
+{
+ return auth_cache_allows (cache, fh, NULL, host_addr, FALSE);
+}
+
+auth_cache_status_t
+auth_cache_allows_write_to_fh (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr)
+{
+ return auth_cache_allows (cache, fh, NULL, host_addr, TRUE);
+}
+
+auth_cache_status_t
+auth_cache_allows_path (struct auth_cache *cache, const char *path,
+ const char *host_addr)
+{
+ return auth_cache_allows (cache, NULL, path, host_addr, FALSE);
}
diff --git a/xlators/nfs/server/src/auth-cache.h b/xlators/nfs/server/src/auth-cache.h
index a3ea5a43ded..de7db6b5545 100644
--- a/xlators/nfs/server/src/auth-cache.h
+++ b/xlators/nfs/server/src/auth-cache.h
@@ -27,6 +27,11 @@ struct auth_cache {
time_t ttl_sec; /* TTL of the auth cache in seconds */
};
+typedef enum {
+ AUTH_CACHE_HOST_ENOENT = -1, /* Host not found in cache */
+ AUTH_CACHE_HOST_EACCES = -2, /* Host explicitly de-authed */
+ AUTH_CACHE_HOST_AUTH_OK = 0, /* Host is fully authed */
+} auth_cache_status_t;
/* Initializes the cache */
struct auth_cache *
@@ -35,17 +40,29 @@ auth_cache_init (time_t ttl_sec);
/* Inserts FH into cache */
int
cache_nfs_fh (struct auth_cache *cache, struct nfs3_fh *fh,
- const char *host_addr, struct export_item *export_item);
+ const char *host_addr, struct export_item *export_item,
+ auth_cache_status_t status);
+
+/* Inserts path into cache */
+int
+cache_nfs_path (struct auth_cache *cache, const char *path,
+ const char *host_addr, struct export_item *export_item,
+ auth_cache_status_t status);
/* Checks if the filehandle cached & writable */
-gf_boolean_t
-is_nfs_fh_cached_and_writeable (struct auth_cache *cache, struct nfs3_fh *fh,
- const char *host_addr);
+auth_cache_status_t
+auth_cache_allows_write_to_fh (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr);
/* Checks if the filehandle is cached */
-gf_boolean_t
-is_nfs_fh_cached (struct auth_cache *cache, struct nfs3_fh *fh,
- const char *host_addr);
+auth_cache_status_t
+auth_cache_allows_fh (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr);
+
+/* Checks if the path is cached */
+auth_cache_status_t
+auth_cache_allows_path (struct auth_cache *cache, const char *path,
+ const char *host_addr);
/* Purge the cache */
void
diff --git a/xlators/nfs/server/src/exports.h b/xlators/nfs/server/src/exports.h
index 0079b9a3deb..a4e15d3f7ef 100644
--- a/xlators/nfs/server/src/exports.h
+++ b/xlators/nfs/server/src/exports.h
@@ -51,23 +51,28 @@ struct export_options {
char *anon_uid; /* anonuid option */
char *sec_type; /* X, for sec=X */
};
+typedef struct export_options export_options_t;
+
struct export_item {
- char *name; /* Name of the export item */
- struct export_options *opts; /* NFS Options */
+ char *name; /* Name of the export item */
+ export_options_t *opts; /* NFS Options */
};
+typedef struct export_item export_item_t;
struct export_dir {
char *dir_name; /* Directory */
dict_t *netgroups; /* Dict of netgroups */
dict_t *hosts; /* Dict of hosts */
};
+typedef struct export_dir export_dir_t;
struct exports_file {
char *filename; /* Filename */
dict_t *exports_dict; /* Dict of export_dir_t */
dict_t *exports_map; /* Map of SuperFastHash(<export>) -> expdir */
};
+typedef struct exports_file exports_file_t;
void
exp_file_deinit (struct exports_file *expfile);
diff --git a/xlators/nfs/server/src/mount3.c b/xlators/nfs/server/src/mount3.c
index 2dbbc0fbc3b..0a3d79af6f0 100644
--- a/xlators/nfs/server/src/mount3.c
+++ b/xlators/nfs/server/src/mount3.c
@@ -1933,9 +1933,23 @@ mnt3_check_cached_fh (struct mount3_state *ms, struct nfs3_fh *fh,
const char *host_addr, gf_boolean_t is_write_op)
{
if (!is_write_op)
- return is_nfs_fh_cached (ms->authcache, fh, host_addr);
+ return auth_cache_allows_fh (ms->authcache, fh, host_addr);
- return is_nfs_fh_cached_and_writeable (ms->authcache, fh, host_addr);
+ return auth_cache_allows_write_to_fh (ms->authcache, fh, host_addr);
+}
+
+/**
+ * mnt3_check_cached_path -- Check if path is cached.
+ *
+ * Calls auxiliary functions based on whether we are checking
+ * a write operation.
+ *
+ */
+int
+mnt3_check_cached_path (struct mount3_state *ms, const char *path,
+ const char *host_addr, gf_boolean_t is_write_op)
+{
+ return auth_cache_allows_path (ms->authcache, path, host_addr);
}
/**
@@ -1969,7 +1983,7 @@ _mnt3_authenticate_req (struct mount3_state *ms, rpcsvc_request_t *req,
char *pathdup = NULL;
size_t dlen = 0;
char *auth_host = NULL;
- gf_boolean_t fh_cached = _gf_false;
+ auth_cache_status_t auth_cache_status = AUTH_CACHE_HOST_ENOENT;
struct export_item *expitem = NULL;
GF_VALIDATE_OR_GOTO (GF_MNT, ms, out);
@@ -1990,12 +2004,24 @@ _mnt3_authenticate_req (struct mount3_state *ms, rpcsvc_request_t *req,
}
/* Check if the filehandle is cached */
- fh_cached = mnt3_check_cached_fh (ms, fh, host_addr_ip, is_write_op);
- if (fh_cached) {
- gf_msg_trace (GF_MNT, 0, "Found cached FH for %s",
- host_addr_ip);
+ auth_cache_status = fh ? mnt3_check_cached_fh (ms, fh, host_addr_ip,
+ is_write_op) :
+ mnt3_check_cached_path (ms, path, host_addr_ip,
+ is_write_op);
+
+ if (auth_cache_status == AUTH_CACHE_HOST_AUTH_OK) {
+ gf_log (GF_MNT, GF_LOG_TRACE, "Found authorized cached "
+ "FH for [%s]!", host_addr_ip);
auth_status_code = 0;
goto free_and_out;
+ } else if (auth_cache_status == AUTH_CACHE_HOST_EACCES) {
+ gf_log (GF_MNT, GF_LOG_TRACE, "Found de-authorized cached "
+ "FH for [%s]!", host_addr_ip);
+ auth_status_code = -EACCES;
+ goto free_and_out;
+ } else {
+ gf_log (GF_MNT, GF_LOG_TRACE, "Cached FH not found for [%s]!",
+ host_addr_ip);
}
/* Check if the IP is authorized */
@@ -2026,10 +2052,20 @@ _mnt3_authenticate_req (struct mount3_state *ms, rpcsvc_request_t *req,
* host if they are null.
*/
if (!authorized_export || !authorized_host) {
- /* Cache the file handle if it was authorized */
- if (fh && auth_status_code == 0)
- cache_nfs_fh (ms->authcache, fh, host_addr_ip, expitem);
+ if (auth_status_code == 0) {
+ auth_cache_status = AUTH_CACHE_HOST_AUTH_OK;
+ } else {
+ auth_cache_status = AUTH_CACHE_HOST_EACCES;
+ }
+ if (fh) {
+ cache_nfs_fh (ms->authcache, fh, host_addr_ip,
+ expitem, auth_cache_status);
+ }
+ if (path) {
+ cache_nfs_path (ms->authcache, path, host_addr_ip,
+ expitem, auth_cache_status);
+ }
goto free_and_out;
}