Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd1d421a authored by Trond Myklebust's avatar Trond Myklebust
Browse files

Merge branch 'rpcsec_gss-from_cel' into linux-next

* rpcsec_gss-from_cel: (21 commits)
  NFS: Retry SETCLIENTID with AUTH_SYS instead of AUTH_NONE
  NFSv4: Don't clear the machine cred when client establish returns EACCES
  NFSv4: Fix issues in nfs4_discover_server_trunking
  NFSv4: Fix the fallback to AUTH_NULL if krb5i is not available
  NFS: Use server-recommended security flavor by default (NFSv3)
  SUNRPC: Don't recognize RPC_AUTH_MAXFLAVOR
  NFS: Use "krb5i" to establish NFSv4 state whenever possible
  NFS: Try AUTH_UNIX when PUTROOTFH gets NFS4ERR_WRONGSEC
  NFS: Use static list of security flavors during root FH lookup recovery
  NFS: Avoid PUTROOTFH when managing leases
  NFS: Clean up nfs4_proc_get_rootfh
  NFS: Handle missing rpc.gssd when looking up root FH
  SUNRPC: Remove EXPORT_SYMBOL_GPL() from GSS mech switch
  SUNRPC: Make gss_mech_get() static
  SUNRPC: Refactor nfsd4_do_encode_secinfo()
  SUNRPC: Consider qop when looking up pseudoflavors
  SUNRPC: Load GSS kernel module by OID
  SUNRPC: Introduce rpcauth_get_pseudoflavor()
  SUNRPC: Define rpcsec_gss_info structure
  NFS: Remove unneeded forward declaration
  ...
parents bdeca1b7 79d852bf
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -201,7 +201,9 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
	if (clp->cl_minorversion != 0)
		__set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
	__set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
	error = nfs_create_rpc_client(clp, timeparms, authflavour);
	error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I);
	if (error == -EINVAL)
		error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_NULL);
	if (error < 0)
		goto error;

+24 −19
Original line number Diff line number Diff line
@@ -134,33 +134,38 @@ static size_t nfs_parse_server_name(char *string, size_t len,
	return ret;
}

/**
 * nfs_find_best_sec - Find a security mechanism supported locally
 * @flavors: List of security tuples returned by SECINFO procedure
 *
 * Return the pseudoflavor of the first security mechanism in
 * "flavors" that is locally supported.  Return RPC_AUTH_UNIX if
 * no matching flavor is found in the array.  The "flavors" array
 * is searched in the order returned from the server, per RFC 3530
 * recommendation.
 */
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
{
	struct gss_api_mech *mech;
	struct xdr_netobj oid;
	int i;
	rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
	rpc_authflavor_t pseudoflavor;
	struct nfs4_secinfo4 *secinfo;
	unsigned int i;

	for (i = 0; i < flavors->num_flavors; i++) {
		struct nfs4_secinfo_flavor *flavor;
		flavor = &flavors->flavors[i];

		if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) {
			pseudoflavor = flavor->flavor;
			break;
		} else if (flavor->flavor == RPC_AUTH_GSS) {
			oid.len  = flavor->gss.sec_oid4.len;
			oid.data = flavor->gss.sec_oid4.data;
			mech = gss_mech_get_by_OID(&oid);
			if (!mech)
				continue;
			pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service);
			gss_mech_put(mech);
		secinfo = &flavors->flavors[i];

		switch (secinfo->flavor) {
		case RPC_AUTH_NULL:
		case RPC_AUTH_UNIX:
		case RPC_AUTH_GSS:
			pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
							&secinfo->flavor_info);
			if (pseudoflavor != RPC_AUTH_MAXFLAVOR)
				return pseudoflavor;
			break;
		}
	}

	return pseudoflavor;
	return RPC_AUTH_UNIX;
}

static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
+56 −36
Original line number Diff line number Diff line
@@ -2547,7 +2547,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl

	auth = rpcauth_create(flavor, server->client);
	if (IS_ERR(auth)) {
		ret = -EIO;
		ret = -EACCES;
		goto out;
	}
	ret = nfs4_lookup_root(server, fhandle, info);
@@ -2555,27 +2555,36 @@ out:
	return ret;
}

/*
 * Retry pseudoroot lookup with various security flavors.  We do this when:
 *
 *   NFSv4.0: the PUTROOTFH operation returns NFS4ERR_WRONGSEC
 *   NFSv4.1: the server does not support the SECINFO_NO_NAME operation
 *
 * Returns zero on success, or a negative NFS4ERR value, or a
 * negative errno value.
 */
static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
			      struct nfs_fsinfo *info)
{
	int i, len, status = 0;
	rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];

	len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array));
	if (len < 0)
		return len;

	for (i = 0; i < len; i++) {
		/* AUTH_UNIX is the default flavor if none was specified,
		 * thus has already been tried. */
		if (flav_array[i] == RPC_AUTH_UNIX)
			continue;
	/* Per 3530bis 15.33.5 */
	static const rpc_authflavor_t flav_array[] = {
		RPC_AUTH_GSS_KRB5P,
		RPC_AUTH_GSS_KRB5I,
		RPC_AUTH_GSS_KRB5,
		RPC_AUTH_UNIX,			/* courtesy */
		RPC_AUTH_NULL,
	};
	int status = -EPERM;
	size_t i;

	for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
		status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
		if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
			continue;
		break;
	}

	/*
	 * -EACCESS could mean that the user doesn't have correct permissions
	 * to access the mount.  It could also mean that we tried to mount
@@ -2588,24 +2597,36 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
	return status;
}

/*
 * get the file handle for the "/" directory on the server
static int nfs4_do_find_root_sec(struct nfs_server *server,
		struct nfs_fh *fhandle, struct nfs_fsinfo *info)
{
	int mv = server->nfs_client->cl_minorversion;
	return nfs_v4_minor_ops[mv]->find_root_sec(server, fhandle, info);
}

/**
 * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
 * @server: initialized nfs_server handle
 * @fhandle: we fill in the pseudo-fs root file handle
 * @info: we fill in an FSINFO struct
 *
 * Returns zero on success, or a negative errno.
 */
int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
			 struct nfs_fsinfo *info)
{
	int minor_version = server->nfs_client->cl_minorversion;
	int status = nfs4_lookup_root(server, fhandle, info);
	if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR))
		/*
		 * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM
		 * by nfs4_map_errors() as this function exits.
		 */
		status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info);
	int status;

	status = nfs4_lookup_root(server, fhandle, info);
	if ((status == -NFS4ERR_WRONGSEC) &&
	    !(server->flags & NFS_MOUNT_SECFLAVOUR))
		status = nfs4_do_find_root_sec(server, fhandle, info);

	if (status == 0)
		status = nfs4_server_capabilities(server, fhandle);
	if (status == 0)
		status = nfs4_do_fsinfo(server, fhandle, info);

	return nfs4_map_errors(status);
}

@@ -3484,12 +3505,21 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
{
	struct nfs4_exception exception = { };
	unsigned long now = jiffies;
	int err;

	do {
		err = nfs4_handle_exception(server,
				_nfs4_do_fsinfo(server, fhandle, fsinfo),
				&exception);
		err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
		if (err == 0) {
			struct nfs_client *clp = server->nfs_client;

			spin_lock(&clp->cl_lock);
			clp->cl_lease_time = fsinfo->lease_time * HZ;
			clp->cl_last_renewal = now;
			spin_unlock(&clp->cl_lock);
			break;
		}
		err = nfs4_handle_exception(server, err, &exception);
	} while (exception.retry);
	return err;
}
@@ -4330,27 +4360,17 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
		struct nfs4_setclientid_res *arg,
		struct rpc_cred *cred)
{
	struct nfs_fsinfo fsinfo;
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
		.rpc_argp = arg,
		.rpc_resp = &fsinfo,
		.rpc_cred = cred,
	};
	unsigned long now;
	int status;

	dprintk("NFS call  setclientid_confirm auth=%s, (client ID %llx)\n",
		clp->cl_rpcclient->cl_auth->au_ops->au_name,
		clp->cl_clientid);
	now = jiffies;
	status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
	if (status == 0) {
		spin_lock(&clp->cl_lock);
		clp->cl_lease_time = fsinfo.lease_time * HZ;
		clp->cl_last_renewal = now;
		spin_unlock(&clp->cl_lock);
	}
	dprintk("NFS reply setclientid_confirm: %d\n", status);
	return status;
}
+11 −49
Original line number Diff line number Diff line
@@ -154,18 +154,6 @@ struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
	return cred;
}

static void nfs4_clear_machine_cred(struct nfs_client *clp)
{
	struct rpc_cred *cred;

	spin_lock(&clp->cl_lock);
	cred = clp->cl_machine_cred;
	clp->cl_machine_cred = NULL;
	spin_unlock(&clp->cl_lock);
	if (cred != NULL)
		put_rpccred(cred);
}

static struct rpc_cred *
nfs4_get_renew_cred_server_locked(struct nfs_server *server)
{
@@ -1776,10 +1764,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
		return -EPERM;
	case -EACCES:
		if (clp->cl_machine_cred == NULL)
			return -EACCES;
		/* Handle case where the user hasn't set up machine creds */
		nfs4_clear_machine_cred(clp);
	case -NFS4ERR_DELAY:
	case -ETIMEDOUT:
	case -EAGAIN:
@@ -1874,31 +1858,18 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
{
	const struct nfs4_state_recovery_ops *ops =
				clp->cl_mvops->reboot_recovery_ops;
	rpc_authflavor_t *flavors, flav, save;
	struct rpc_clnt *clnt;
	struct rpc_cred *cred;
	int i, len, status;
	int i, status;

	dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname);

	len = NFS_MAX_SECFLAVORS;
	flavors = kcalloc(len, sizeof(*flavors), GFP_KERNEL);
	if (flavors == NULL) {
		status = -ENOMEM;
		goto out;
	}
	len = rpcauth_list_flavors(flavors, len);
	if (len < 0) {
		status = len;
		goto out_free;
	}
	clnt = clp->cl_rpcclient;
	save = clnt->cl_auth->au_flavor;
	i = 0;

	mutex_lock(&nfs_clid_init_mutex);
	status  = -ENOENT;
again:
	status  = -ENOENT;
	cred = ops->get_clid_cred(clp);
	if (cred == NULL)
		goto out_unlock;
@@ -1908,12 +1879,6 @@ again:
	switch (status) {
	case 0:
		break;

	case -EACCES:
		if (clp->cl_machine_cred == NULL)
			break;
		/* Handle case where the user hasn't set up machine creds */
		nfs4_clear_machine_cred(clp);
	case -NFS4ERR_DELAY:
	case -ETIMEDOUT:
	case -EAGAIN:
@@ -1922,17 +1887,12 @@ again:
		dprintk("NFS: %s after status %d, retrying\n",
			__func__, status);
		goto again;

	case -EACCES:
		if (i++)
			break;
	case -NFS4ERR_CLID_INUSE:
	case -NFS4ERR_WRONGSEC:
		status = -EPERM;
		if (i >= len)
			break;

		flav = flavors[i++];
		if (flav == save)
			flav = flavors[i++];
		clnt = rpc_clone_client_set_auth(clnt, flav);
		clnt = rpc_clone_client_set_auth(clnt, RPC_AUTH_UNIX);
		if (IS_ERR(clnt)) {
			status = PTR_ERR(clnt);
			break;
@@ -1948,13 +1908,15 @@ again:
	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
				 * in nfs4_exchange_id */
		status = -EKEYEXPIRED;
		break;
	default:
		pr_warn("NFS: %s unhandled error %d. Exiting with error EIO\n",
				__func__, status);
		status = -EIO;
	}

out_unlock:
	mutex_unlock(&nfs_clid_init_mutex);
out_free:
	kfree(flavors);
out:
	dprintk("NFS: %s: status = %d\n", __func__, status);
	return status;
}
+2 −0
Original line number Diff line number Diff line
@@ -252,6 +252,8 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,

	dfprintk(MOUNT, "--> nfs4_try_mount()\n");

	if (data->auth_flavors[0] == RPC_AUTH_MAXFLAVOR)
		data->auth_flavors[0] = RPC_AUTH_UNIX;
	export_path = data->nfs_server.export_path;
	data->nfs_server.export_path = "/";
	root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
Loading