/* Covert GPFS NFS4 ACLs to FSAL ACLs, and set the ACL
 * pointer of attribute. */
static int gpfs_acl_2_fsal_acl(struct attrlist * p_object_attributes,
	                      gpfs_acl_t *p_gpfsacl)
{
  fsal_acl_status_t status;
  fsal_acl_data_t acldata;
  fsal_ace_t *pace;
  fsal_acl_t *pacl;
  gpfs_ace_v4_t *pace_gpfs;

  /* sanity checks */
  if(!p_object_attributes || !p_gpfsacl)
    return ERR_FSAL_FAULT;

  /* Create fsal acl data. */
  acldata.naces = p_gpfsacl->acl_nace;
  acldata.aces = (fsal_ace_t *)nfs4_ace_alloc(acldata.naces);

  /* Fill fsal acl data from gpfs acl. */
  for(pace = acldata.aces, pace_gpfs = p_gpfsacl->ace_v4;
      pace < acldata.aces + acldata.naces; pace++, pace_gpfs++)
    {
      pace->type = pace_gpfs->aceType;
      pace->flag = pace_gpfs->aceFlags;
      pace->iflag = pace_gpfs->aceIFlags;
      pace->perm = pace_gpfs->aceMask;

      if(IS_FSAL_ACE_SPECIAL_ID(*pace))  /* Record special user. */
        {
          pace->who.uid = pace_gpfs->aceWho;
        }
        else
        {
          if(IS_FSAL_ACE_GROUP_ID(*pace))  /* Record group. */
            pace->who.gid = pace_gpfs->aceWho;
          else  /* Record user. */
            pace->who.uid = pace_gpfs->aceWho;
        }

        LogDebug(COMPONENT_FSAL,
                 "gpfs_acl_2_fsal_acl: fsal ace: type = 0x%x, flag = 0x%x, perm = 0x%x, special = %d, %s = 0x%x",
                 pace->type, pace->flag, pace->perm, IS_FSAL_ACE_SPECIAL_ID(*pace),
                 GET_FSAL_ACE_WHO_TYPE(*pace), GET_FSAL_ACE_WHO(*pace));
    }

  /* Create a new hash table entry for fsal acl. */
  pacl = nfs4_acl_new_entry(&acldata, &status);
  LogDebug(COMPONENT_FSAL, "fsal acl = %p, fsal_acl_status = %u", pacl, status);

  if(pacl == NULL)
    {
      LogCrit(COMPONENT_FSAL, "gpfs_acl_2_fsal_acl: failed to create a new acl entry");
      return ERR_FSAL_FAULT;
    }

  /* Add fsal acl to attribute. */
  p_object_attributes->acl = pacl;

  return ERR_FSAL_NO_ERROR;
}
Beispiel #2
0
static bool fsal_check_ace_matches(fsal_ace_t *pace, struct user_cred *creds,
				   bool is_owner, bool is_group)
{
	bool result = false;
	char *cause = "";

	if (IS_FSAL_ACE_SPECIAL_ID(*pace))
		switch (pace->who.uid) {
		case FSAL_ACE_SPECIAL_OWNER:
			if (is_owner) {
				result = true;
				cause = "special owner";
			}
			break;

		case FSAL_ACE_SPECIAL_GROUP:
			if (is_group) {
				result = true;
				cause = "special group";
			}
			break;

		case FSAL_ACE_SPECIAL_EVERYONE:
			result = true;
			cause = "special everyone";
			break;

		default:
			break;
	} else if (IS_FSAL_ACE_GROUP_ID(*pace)) {
		if (fsal_check_ace_group(pace->who.gid, creds)) {
			result = true;
			cause = "group";
		}
	} else {
		if (fsal_check_ace_owner(pace->who.uid, creds)) {
			result = true;
			cause = "owner";
		}
	}

	LogFullDebug(COMPONENT_NFS_V4_ACL,
		     "result: %d, cause: %s, flag: 0x%X, who: %d", result,
		     cause, pace->flag, GET_FSAL_ACE_WHO(*pace));

	return result;
}
Beispiel #3
0
static void fsal_print_ace(int ace_number, fsal_ace_t *pace, char *p_acebuf)
{
  char inherit_flags[ACL_DEBUG_BUF_SIZE];

  if(!pace || !p_acebuf)
    return;

  memset(p_acebuf, 0, ACL_DEBUG_BUF_SIZE);
  memset(inherit_flags, 0, ACL_DEBUG_BUF_SIZE);

  /* Get inherit flags if any. */
  fsal_print_inherit_flags(pace, inherit_flags);

  /* Print the entire ACE. */
  sprintf(p_acebuf, "ACE %d %s %s %d %c%c%c%c%c%c%c%c%c%c%c%c%c%c %s",
          ace_number,
          /* ACE type. */
          IS_FSAL_ACE_ALLOW(*pace)? "allow":
          IS_FSAL_ACE_DENY(*pace) ? "deny":
          IS_FSAL_ACE_AUDIT(*pace)? "audit": "?",
          /* ACE who and its type. */
          (IS_FSAL_ACE_SPECIAL_ID(*pace) && IS_FSAL_ACE_SPECIAL_OWNER(*pace))    ? "owner@":
          (IS_FSAL_ACE_SPECIAL_ID(*pace) && IS_FSAL_ACE_SPECIAL_GROUP(*pace))    ? "group@":
          (IS_FSAL_ACE_SPECIAL_ID(*pace) && IS_FSAL_ACE_SPECIAL_EVERYONE(*pace)) ? "everyone@":
          IS_FSAL_ACE_SPECIAL_ID(*pace)						 ? "specialid":
          IS_FSAL_ACE_GROUP_ID(*pace) 						 ? "gid": "uid",
          GET_FSAL_ACE_WHO(*pace),
          /* ACE mask. */
          IS_FSAL_ACE_READ_DATA(*pace)		 ? 'r':'-',
          IS_FSAL_ACE_WRITE_DATA(*pace)		 ? 'w':'-',
          IS_FSAL_ACE_EXECUTE(*pace)		 ? 'x':'-',
          IS_FSAL_ACE_ADD_SUBDIRECTORY(*pace)    ? 'm':'-',
          IS_FSAL_ACE_READ_NAMED_ATTR(*pace)	 ? 'n':'-',
          IS_FSAL_ACE_WRITE_NAMED_ATTR(*pace) 	 ? 'N':'-',
          IS_FSAL_ACE_DELETE_CHILD(*pace) 	 ? 'p':'-',
          IS_FSAL_ACE_READ_ATTR(*pace)		 ? 't':'-',
          IS_FSAL_ACE_WRITE_ATTR(*pace)		 ? 'T':'-',
          IS_FSAL_ACE_DELETE(*pace)		 ? 'd':'-',
          IS_FSAL_ACE_READ_ACL(*pace) 		 ? 'c':'-',
          IS_FSAL_ACE_WRITE_ACL(*pace)		 ? 'C':'-',
          IS_FSAL_ACE_WRITE_OWNER(*pace)	 ? 'o':'-',
          IS_FSAL_ACE_SYNCHRONIZE(*pace)	 ? 'z':'-',
          /* ACE Inherit flags. */
          IS_FSAL_ACE_INHERIT(*pace)? inherit_flags: "");
}
Beispiel #4
0
static fsal_boolean_t fsal_check_ace_matches(fsal_ace_t *pace,
                                             fsal_op_context_t *p_context,
                                             fsal_boolean_t is_owner,
                                             fsal_boolean_t is_group)
{
  int matches = 0;

  if (IS_FSAL_ACE_SPECIAL_ID(*pace))
    switch(pace->who.uid)
      {
        case FSAL_ACE_SPECIAL_OWNER:
          if(is_owner)
            matches = 1;
        break;

        case FSAL_ACE_SPECIAL_GROUP:
          if(is_group)
            matches = 2;
        break;

        case FSAL_ACE_SPECIAL_EVERYONE:
          matches = 3;
        break;

        default:
        break;
      }
  else if (IS_FSAL_ACE_GROUP_ID(*pace))
    {
      if(fsal_check_ace_group(pace->who.gid, p_context))
        matches = 4;
    }
  else
    {
      if(fsal_check_ace_owner(pace->who.uid, p_context))
        matches = 5;
    }

  LogDebug(COMPONENT_FSAL,
           "fsal_check_ace_matches: matches %d flag 0x%X who %d",
           matches, pace->flag, GET_FSAL_ACE_WHO(*pace));

  return (matches != 0);
}
Beispiel #5
0
static fsal_status_t fsal_check_access_acl(struct user_cred *creds,
					   fsal_aceperm_t v4mask,
					   fsal_accessflags_t *allowed,
					   fsal_accessflags_t *denied,
					   struct attrlist *p_object_attributes)
{
	fsal_aceperm_t missing_access;
	fsal_aceperm_t tperm;
	uid_t uid;
	gid_t gid;
	fsal_acl_t *pacl = NULL;
	fsal_ace_t *pace = NULL;
	int ace_number = 0;
	bool is_dir = false;
	bool is_owner = false;
	bool is_group = false;
	bool is_root = false;

	if (allowed != NULL)
		*allowed = 0;

	if (denied != NULL)
		*denied = 0;

	if (!p_object_attributes->acl) {
		/* Means that FSAL_ACE4_REQ_FLAG was set, but no ACLs */
		LogFullDebug(COMPONENT_NFS_V4_ACL,
			     "Allow ACE required, but no ACLs");
		return fsalstat(ERR_FSAL_NO_ACE, 0);
	}

	/* unsatisfied flags */
	missing_access = v4mask & ~FSAL_ACE4_PERM_CONTINUE;
	if (!missing_access) {
		LogFullDebug(COMPONENT_NFS_V4_ACL, "Nothing was requested");
		return fsalstat(ERR_FSAL_NO_ERROR, 0);
	}

	/* Get file ownership information. */
	uid = p_object_attributes->owner;
	gid = p_object_attributes->group;
	pacl = p_object_attributes->acl;
	is_dir = (p_object_attributes->type == DIRECTORY);
	is_root = creds->caller_uid == 0;

	if (is_root) {
		if (is_dir) {
			if (allowed != NULL)
				*allowed = v4mask;

			/* On a directory, allow root anything. */
			LogFullDebug(COMPONENT_NFS_V4_ACL,
				     "Met root privileges on directory");
			return fsalstat(ERR_FSAL_NO_ERROR, 0);
		}

		/* Otherwise, allow root anything but execute. */
		missing_access &= FSAL_ACE_PERM_EXECUTE;

		if (allowed != NULL)
			*allowed = v4mask & ~FSAL_ACE_PERM_EXECUTE;

		if (!missing_access) {
			LogFullDebug(COMPONENT_NFS_V4_ACL,
				     "Met root privileges");
			return fsalstat(ERR_FSAL_NO_ERROR, 0);
		}
	}

	LogFullDebug(COMPONENT_NFS_V4_ACL,
		     "file acl=%p, file uid=%u, file gid=%u, ", pacl, uid, gid);

	if (isFullDebug(COMPONENT_NFS_V4_ACL)) {
		char str[LOG_BUFF_LEN];
		struct display_buffer dspbuf = { sizeof(str), str, str };

		(void)display_fsal_v4mask(&dspbuf, v4mask,
					  p_object_attributes->type ==
					  DIRECTORY);

		LogFullDebug(COMPONENT_NFS_V4_ACL,
			     "user uid=%u, user gid= %u, v4mask=%s",
			     creds->caller_uid, creds->caller_gid, str);
	}

	is_owner = fsal_check_ace_owner(uid, creds);
	is_group = fsal_check_ace_group(gid, creds);

	/* Always grant READ_ACL, WRITE_ACL and READ_ATTR, WRITE_ATTR
	 * to the file owner. */
	if (is_owner) {
		if (allowed != NULL)
			*allowed |=
			    v4mask & (FSAL_ACE_PERM_WRITE_ACL |
				      FSAL_ACE_PERM_READ_ACL |
				      FSAL_ACE_PERM_WRITE_ATTR |
				      FSAL_ACE_PERM_READ_ATTR);

		missing_access &=
		    ~(FSAL_ACE_PERM_WRITE_ACL | FSAL_ACE_PERM_READ_ACL);
		missing_access &=
		    ~(FSAL_ACE_PERM_WRITE_ATTR | FSAL_ACE_PERM_READ_ATTR);
		if (!missing_access) {
			LogFullDebug(COMPONENT_NFS_V4_ACL,
				     "Met owner privileges");
			return fsalstat(ERR_FSAL_NO_ERROR, 0);
		}
	}
	/** @todo Even if user is admin, audit/alarm checks should be done. */

	for (pace = pacl->aces; pace < pacl->aces + pacl->naces; pace++) {
		ace_number += 1;

		LogFullDebug(COMPONENT_NFS_V4_ACL,
			     "ace numnber: %d ace type 0x%X perm 0x%X flag 0x%X who %u",
			     ace_number, pace->type, pace->perm, pace->flag,
			     GET_FSAL_ACE_WHO(*pace));

		/* Process Allow and Deny entries. */
		if (!IS_FSAL_ACE_ALLOW(*pace) && !IS_FSAL_ACE_DENY(*pace)) {
			LogFullDebug(COMPONENT_NFS_V4_ACL, "not allow or deny");
			continue;
		}

		LogFullDebug(COMPONENT_NFS_V4_ACL, "allow or deny");

		/* Check if this ACE is applicable. */
		if (fsal_check_ace_applicable(pace, creds, is_dir, is_owner,
					      is_group, is_root)) {
			if (IS_FSAL_ACE_ALLOW(*pace)) {
				/* Do not set bits which are already denied */
				if (denied)
					tperm = pace->perm & ~*denied;
				else
					tperm = pace->perm;

				LogFullDebug(COMPONENT_NFS_V4_ACL,
					     "allow perm 0x%X remainingPerms 0x%X",
					     tperm, missing_access);

				if (allowed != NULL)
					*allowed |= v4mask & tperm;

				missing_access &=
				    ~(tperm & missing_access);

				if (!missing_access) {
					fsal_print_access_by_acl(
							pacl->naces,
							ace_number,
							pace,
							v4mask,
							ERR_FSAL_NO_ERROR,
							is_dir,
							creds);
					break;
				}
			} else if ((pace->perm & missing_access) && !is_root) {
				fsal_print_access_by_acl(
					pacl->naces,
					ace_number,
					pace,
					v4mask,
#ifndef ENABLE_RFC_ACL
					(pace->perm & missing_access &
					 (FSAL_ACE_PERM_WRITE_ATTR |
					  FSAL_ACE_PERM_WRITE_ACL |
					  FSAL_ACE_PERM_WRITE_OWNER))
					    != 0 ?
					    ERR_FSAL_PERM :
#endif /* ENABLE_RFC_ACL */
					    ERR_FSAL_ACCESS,
					is_dir,
					creds);

				if (denied != NULL)
					*denied |= v4mask & pace->perm;
				if (denied == NULL ||
				    (v4mask &
				     FSAL_ACE4_PERM_CONTINUE) == 0) {
#ifndef ENABLE_RFC_ACL
					if ((pace->perm & missing_access &
					    (FSAL_ACE_PERM_WRITE_ATTR |
					     FSAL_ACE_PERM_WRITE_ACL |
					     FSAL_ACE_PERM_WRITE_OWNER))
					    != 0) {
						LogDebug(COMPONENT_NFS_V4_ACL,
							 "access denied (EPERM)");
						return fsalstat(ERR_FSAL_PERM,
							0);
					} else {
						LogDebug(COMPONENT_NFS_V4_ACL,
							 "access denied (EACCESS)");
						return fsalstat(ERR_FSAL_ACCESS,
							0);
					}
#else /* ENABLE_RFC_ACL */
					LogDebug(COMPONENT_NFS_V4_ACL,
						 "access denied (EACCESS)");
					return fsalstat(ERR_FSAL_ACCESS, 0);
#endif /* ENABLE_RFC_ACL */
				}

				missing_access &=
				    ~(pace->perm & missing_access);

				/* If this DENY ACE blocked the last
				 * remaining requested access
				 * bits, break out of the loop because
				 * we're done and don't
				 * want to evaluate any more ACEs.
				 */
				if (!missing_access)
					break;
			}
		}
	}

	if (IS_FSAL_ACE4_REQ(v4mask) && missing_access) {
		LogDebug(COMPONENT_NFS_V4_ACL, "final access unknown (NO_ACE)");
		return fsalstat(ERR_FSAL_NO_ACE, 0);
	} else if (missing_access || (denied != NULL && *denied != 0)) {
#ifndef ENABLE_RFC_ACL
		if ((missing_access &
		     (FSAL_ACE_PERM_WRITE_ATTR | FSAL_ACE_PERM_WRITE_ACL |
		      FSAL_ACE_PERM_WRITE_OWNER)) != 0) {
			LogDebug(COMPONENT_NFS_V4_ACL,
				 "final access denied (EPERM)");
			return fsalstat(ERR_FSAL_PERM, 0);
		} else {
			LogDebug(COMPONENT_NFS_V4_ACL,
				 "final access denied (EACCESS)");
			return fsalstat(ERR_FSAL_ACCESS, 0);
		}
#else /* ENABLE_RFC_ACL */
		LogDebug(COMPONENT_NFS_V4_ACL, "final access denied (EACCESS)");
		return fsalstat(ERR_FSAL_ACCESS, 0);
#endif /* ENABLE_RFC_ACL */
	} else {
		LogFullDebug(COMPONENT_NFS_V4_ACL, "access granted");
		return fsalstat(ERR_FSAL_NO_ERROR, 0);
	}
}
Beispiel #6
0
static fsal_status_t fsal_check_access_acl(fsal_op_context_t * p_context,   /* IN */
                                                  fsal_aceperm_t v4mask,  /* IN */
                                                  fsal_attrib_list_t * p_object_attributes   /* IN */ )
{
  fsal_aceperm_t missing_access;
  fsal_uid_t uid;
  fsal_gid_t gid;
  fsal_acl_t *pacl = NULL;
  fsal_ace_t *pace = NULL;
  int ace_number = 0;
  fsal_boolean_t is_dir = FALSE;
  fsal_boolean_t is_owner = FALSE;
  fsal_boolean_t is_group = FALSE;

  /* unsatisfied flags */
  missing_access = v4mask;
  if(!missing_access)
    {
      LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: Nothing was requested");
      ReturnCode(ERR_FSAL_NO_ERROR, 0);
    }

  /* Get file ownership information. */
  uid = p_object_attributes->owner;
  gid = p_object_attributes->group;
  pacl = p_object_attributes->acl;
  is_dir = (p_object_attributes->type == FSAL_TYPE_DIR);

  LogDebug(COMPONENT_FSAL,
           "fsal_check_access_acl: file acl=%p, file uid=%d, file gid= %d",
           pacl,uid, gid);
  LogDebug(COMPONENT_FSAL,
           "fsal_check_access_acl: user uid=%d, user gid= %d, v4mask=0x%X",
           p_context->credential.user,
           p_context->credential.group,
           v4mask);

  is_owner = fsal_check_ace_owner(uid, p_context);
  is_group = fsal_check_ace_group(gid, p_context);

  /* Always grant READ_ACL, WRITE_ACL and READ_ATTR, WRITE_ATTR to the file
   * owner. */
  if(is_owner)
    {
      missing_access &= ~(FSAL_ACE_PERM_WRITE_ACL | FSAL_ACE_PERM_READ_ACL);
      missing_access &= ~(FSAL_ACE_PERM_WRITE_ATTR | FSAL_ACE_PERM_READ_ATTR);
      if(!missing_access)
        {
          LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: Met owner privileges");
          ReturnCode(ERR_FSAL_NO_ERROR, 0);
        }
    }

  // TODO: Even if user is admin, audit/alarm checks should be done.

  ace_number = 1;
  for(pace = pacl->aces; pace < pacl->aces + pacl->naces; pace++)
    {
      LogDebug(COMPONENT_FSAL,
               "fsal_check_access_acl: ace type 0x%X perm 0x%X flag 0x%X who %d",
               pace->type, pace->perm, pace->flag, GET_FSAL_ACE_WHO(*pace));

      /* Process Allow and Deny entries. */
      if(IS_FSAL_ACE_ALLOW(*pace) || IS_FSAL_ACE_DENY(*pace))
        {
          LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: allow or deny");

          /* Check if this ACE is applicable. */
          if(fsal_check_ace_applicable(pace, p_context, is_dir, is_owner, is_group))
            {
              if(IS_FSAL_ACE_ALLOW(*pace))
                {
                  LogDebug(COMPONENT_FSAL,
                           "fsal_check_access_acl: allow perm 0x%X remainingPerms 0x%X",
                           pace->perm, missing_access);

                  missing_access &= ~(pace->perm & missing_access);
                  if(!missing_access)
                    {
                      LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: access granted");
                      fsal_print_access_by_acl(pacl->naces, ace_number, pace,
                                                     v4mask, ERR_FSAL_NO_ERROR, is_dir, p_context);
                      ReturnCode(ERR_FSAL_NO_ERROR, 0);
                    }
                }
             else if(pace->perm & missing_access)
               {
                 LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: access denied");
                 fsal_print_access_by_acl(pacl->naces, ace_number, pace, v4mask,
                                                ERR_FSAL_ACCESS, is_dir, p_context);
                 ReturnCode(ERR_FSAL_ACCESS, 0);
               }
            }
        }

        ace_number += 1;
    }

  if(missing_access)
    {
      LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: access denied");
      ReturnCode(ERR_FSAL_ACCESS, 0);
    }
  else
    {
      LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: access granted");
      ReturnCode(ERR_FSAL_NO_ERROR, 0);
    }

  ReturnCode(ERR_FSAL_NO_ERROR, 0);
}
/**
 *
 * cache_inode_getattr: Gets the attributes for a cached entry.
 *
 * Gets the attributes for a cached entry. The FSAL attributes are kept in a structure when the entry
 * is added to the cache.
 *
 * @param pentry [IN] entry to be managed.
 * @param pattr [OUT] pointer to the results
 * @param ht [IN] hash table used for the cache, unused in this call.
 * @param pclient [INOUT] ressource allocated by the client for the nfs management.
 * @param pcontext [IN] FSAL credentials
 * @param pstatus [OUT] returned status.
 *
 * @return CACHE_INODE_SUCCESS if operation is a success \n
 * @return CACHE_INODE_LRU_ERROR if allocation error occured when validating the entry
 *
 */
cache_inode_status_t
cache_inode_getattr(cache_entry_t * pentry,
                    fsal_attrib_list_t * pattr,
                    hash_table_t * ht, /* Unused, kept for protototype's homogeneity */
                    cache_inode_client_t * pclient,
                    fsal_op_context_t * pcontext,
                    cache_inode_status_t * pstatus)
{
    cache_inode_status_t status;
    fsal_handle_t *pfsal_handle = NULL;
    fsal_status_t fsal_status;

    /* sanity check */
    if(pentry == NULL || pattr == NULL ||
       ht == NULL || pclient == NULL || pcontext == NULL)
        {
            *pstatus = CACHE_INODE_INVALID_ARGUMENT;
            LogDebug(COMPONENT_CACHE_INODE,
                     "cache_inode_getattr: returning CACHE_INODE_INVALID_ARGUMENT because of bad arg");
            return *pstatus;
        }

    /* Set the return default to CACHE_INODE_SUCCESS */
    *pstatus = CACHE_INODE_SUCCESS;

    /* stats */
    pclient->stat.nb_call_total += 1;
    inc_func_call(pclient, CACHE_INODE_GETATTR);

    /* Lock the entry */
    P_w(&pentry->lock);
    status = cache_inode_renew_entry(pentry, pattr, ht,
                                     pclient, pcontext, pstatus);
    if(status != CACHE_INODE_SUCCESS)
        {
            V_w(&pentry->lock);
            inc_func_err_retryable(pclient, CACHE_INODE_GETATTR);
            LogFullDebug(COMPONENT_CACHE_INODE,
                         "cache_inode_getattr: returning %d(%s) from cache_inode_renew_entry",
                         *pstatus, cache_inode_err_str(*pstatus));
            return *pstatus;
        }

    /* RW Lock goes for writer to reader */
    rw_lock_downgrade(&pentry->lock);

    cache_inode_get_attributes(pentry, pattr);

    if(FSAL_TEST_MASK(pattr->asked_attributes,
                      FSAL_ATTR_RDATTR_ERR))
        {
            switch (pentry->internal_md.type)
                {
                case REGULAR_FILE:
                    pfsal_handle = &pentry->object.file.handle;
                    break;

                case SYMBOLIC_LINK:
                    assert(pentry->object.symlink);
                    pfsal_handle = &pentry->object.symlink->handle;
                    break;

                case DIRECTORY:
                    pfsal_handle = &pentry->object.dir.handle;
                    break;
                case SOCKET_FILE:
                case FIFO_FILE:
                case BLOCK_FILE:
                case CHARACTER_FILE:
                    pfsal_handle = &pentry->object.special_obj.handle;
                    break;
                case FS_JUNCTION:
                case UNASSIGNED:
                case RECYCLED:
                    *pstatus = CACHE_INODE_INVALID_ARGUMENT;
                    LogFullDebug(COMPONENT_CACHE_INODE,
                                 "cache_inode_getattr: returning %d(%s) from cache_inode_renew_entry - unexpected md_type",
                                 *pstatus, cache_inode_err_str(*pstatus));
                    return *pstatus;
                }

            /*
             * An error occured when trying to get
             * the attributes, they have to be renewed
             */
#ifdef _USE_MFSL
            fsal_status = FSAL_getattrs_descriptor(&(cache_inode_fd(pentry)->fsal_file), pfsal_handle, pcontext, pattr);
#else
            fsal_status = FSAL_getattrs_descriptor(cache_inode_fd(pentry), pfsal_handle, pcontext, pattr);
#endif
            if(FSAL_IS_ERROR(fsal_status))
                {
                    *pstatus = cache_inode_error_convert(fsal_status);
                    
                    V_r(&pentry->lock);

                    if(fsal_status.major == ERR_FSAL_STALE)
                        {
                            cache_inode_status_t kill_status;

                            LogEvent(COMPONENT_CACHE_INODE,
                                     "cache_inode_getattr: Stale FSAL File Handle detected for pentry = %p",
                                     pentry);

                            /* Locked flag is set to true to show entry has a read lock */
                            cache_inode_kill_entry( pentry, WT_LOCK, ht,
                                                    pclient, &kill_status);
                            if(kill_status != CACHE_INODE_SUCCESS)
                                LogCrit(COMPONENT_CACHE_INODE,
                                        "cache_inode_getattr: Could not kill entry %p, status = %u",
                                        pentry, kill_status);

                            *pstatus = CACHE_INODE_FSAL_ESTALE;
                        }

                    /* stat */
                    inc_func_err_unrecover(pclient, CACHE_INODE_GETATTR);
                    LogDebug(COMPONENT_CACHE_INODE,
                             "cache_inode_getattr: returning %d(%s) from FSAL_getattrs_descriptor",
                             *pstatus, cache_inode_err_str(*pstatus));
                    return *pstatus;
                }

            /* Set the new attributes */
            cache_inode_set_attributes(pentry, pattr);
        }
    *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient);

    V_r(&pentry->lock);

    /* stat */
    if(*pstatus != CACHE_INODE_SUCCESS)
        inc_func_err_retryable(pclient, CACHE_INODE_GETATTR);
    else
        inc_func_success(pclient, CACHE_INODE_GETATTR);

#ifdef _USE_NFS4_ACL
    if(isDebug(COMPONENT_NFS_V4_ACL))
      {
        LogDebug(COMPONENT_CACHE_INODE,
                 "cache_inode_getattr: pentry = %p, acl = %p",
                 pentry, pattr->acl);

        if(pattr->acl)
          {
            fsal_ace_t *pace;
            for(pace = pattr->acl->aces; pace < pattr->acl->aces + pattr->acl->naces; pace++)
              {
                LogDebug(COMPONENT_CACHE_INODE,
                         "cache_inode_getattr: ace type = 0x%x, flag = 0x%x, perm = 0x%x, special = %d, %s = 0x%x",
                         pace->type, pace->flag, pace->perm, IS_FSAL_ACE_SPECIAL_ID(*pace),
                         GET_FSAL_ACE_WHO_TYPE(*pace), GET_FSAL_ACE_WHO(*pace));
              }
          }
      }
#endif                          /* _USE_NFS4_ACL */

    LogFullDebug(COMPONENT_CACHE_INODE,
                 "cache_inode_getattr: returning %d(%s) from cache_inode_valid",
                 *pstatus, cache_inode_err_str(*pstatus));
    return *pstatus;
}