NFS/SUNRPC: don't lookup machine credential until rpcauth_bindcred().
When NFS creates a machine credential, it is a "generic" credential, not tied to any auth protocol, and is really just a container for the princpal name. This doesn't get linked to a genuine credential until rpcauth_bindcred() is called. The lookup always succeeds, so various places that test if the machine credential is NULL, are pointless. As a step towards getting rid of generic credentials, this patch gets rid of generic machine credentials. The nfs_client and rpc_client just hold a pointer to a constant principal name. When a machine credential is wanted, a special static 'struct rpc_cred' pointer is used. rpcauth_bindcred() recognizes this, finds the principal from the client, and binds the correct credential. Signed-off-by: NeilBrown <neilb@suse.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
parent
ecd5f97e1c
commit
5e16923b43
|
@ -151,7 +151,6 @@ EXPORT_SYMBOL_GPL(unregister_nfs_version);
|
|||
struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
|
||||
{
|
||||
struct nfs_client *clp;
|
||||
struct rpc_cred *cred;
|
||||
int err = -ENOMEM;
|
||||
|
||||
if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
|
||||
|
@ -182,9 +181,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
|
|||
clp->cl_proto = cl_init->proto;
|
||||
clp->cl_net = get_net(cl_init->net);
|
||||
|
||||
cred = rpc_lookup_machine_cred("*");
|
||||
if (!IS_ERR(cred))
|
||||
clp->cl_machine_cred = cred;
|
||||
clp->cl_principal = "*";
|
||||
nfs_fscache_get_client_cookie(clp);
|
||||
|
||||
return clp;
|
||||
|
@ -246,11 +243,6 @@ void nfs_free_client(struct nfs_client *clp)
|
|||
if (!IS_ERR(clp->cl_rpcclient))
|
||||
rpc_shutdown_client(clp->cl_rpcclient);
|
||||
|
||||
if (clp->cl_machine_cred != NULL)
|
||||
put_rpccred(clp->cl_machine_cred);
|
||||
if (clp->cl_root_cred != NULL)
|
||||
put_rpccred(clp->cl_root_cred);
|
||||
|
||||
put_net(clp->cl_net);
|
||||
put_nfs_version(clp->cl_nfs_mod);
|
||||
kfree(clp->cl_hostname);
|
||||
|
@ -529,6 +521,7 @@ int nfs_create_rpc_client(struct nfs_client *clp,
|
|||
return PTR_ERR(clnt);
|
||||
}
|
||||
|
||||
clnt->cl_principal = clp->cl_principal;
|
||||
clp->cl_rpcclient = clnt;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -338,7 +338,6 @@ static inline bool
|
|||
_nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode,
|
||||
struct rpc_clnt **clntp, struct rpc_message *msg)
|
||||
{
|
||||
struct rpc_cred *newcred = NULL;
|
||||
rpc_authflavor_t flavor;
|
||||
|
||||
if (sp4_mode == NFS_SP4_MACH_CRED_CLEANUP ||
|
||||
|
@ -353,13 +352,7 @@ _nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode,
|
|||
return false;
|
||||
}
|
||||
if (test_bit(sp4_mode, &clp->cl_sp4_flags)) {
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (clp->cl_machine_cred != NULL)
|
||||
/* don't call get_rpccred on the machine cred -
|
||||
* a reference will be held for life of clp */
|
||||
newcred = clp->cl_machine_cred;
|
||||
spin_unlock(&clp->cl_lock);
|
||||
msg->rpc_cred = newcred;
|
||||
msg->rpc_cred = rpc_machine_cred();
|
||||
|
||||
flavor = clp->cl_rpcclient->cl_auth->au_flavor;
|
||||
WARN_ON_ONCE(flavor != RPC_AUTH_GSS_KRB5I &&
|
||||
|
|
|
@ -166,28 +166,15 @@ out:
|
|||
|
||||
struct rpc_cred *nfs4_get_machine_cred(struct nfs_client *clp)
|
||||
{
|
||||
struct rpc_cred *cred = clp->cl_root_cred;
|
||||
|
||||
if (!cred)
|
||||
cred = clp->cl_machine_cred;
|
||||
if (cred)
|
||||
return get_rpccred(cred);
|
||||
return cred;
|
||||
return get_rpccred(rpc_machine_cred());
|
||||
}
|
||||
|
||||
static void nfs4_root_machine_cred(struct nfs_client *clp)
|
||||
{
|
||||
struct rpc_cred *new;
|
||||
|
||||
new = rpc_lookup_machine_cred(NULL);
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (clp->cl_root_cred == NULL) {
|
||||
clp->cl_root_cred = new;
|
||||
new = NULL;
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
if (new != NULL)
|
||||
put_rpccred(new);
|
||||
/* Force root creds instead of machine */
|
||||
clp->cl_principal = NULL;
|
||||
clp->cl_rpcclient->cl_principal = NULL;
|
||||
}
|
||||
|
||||
static struct rpc_cred *
|
||||
|
|
|
@ -847,14 +847,10 @@ static int max_cb_time(struct net *net)
|
|||
static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses)
|
||||
{
|
||||
if (clp->cl_minorversion == 0) {
|
||||
char *principal = clp->cl_cred.cr_targ_princ ?
|
||||
clp->cl_cred.cr_targ_princ : "nfs";
|
||||
struct rpc_cred *cred;
|
||||
client->cl_principal = clp->cl_cred.cr_targ_princ ?
|
||||
clp->cl_cred.cr_targ_princ : "nfs";
|
||||
|
||||
cred = rpc_lookup_machine_cred(principal);
|
||||
if (!IS_ERR(cred))
|
||||
get_rpccred(cred);
|
||||
return cred;
|
||||
return get_rpccred(rpc_machine_cred());
|
||||
} else {
|
||||
struct rpc_auth *auth = client->cl_auth;
|
||||
struct auth_cred acred = {};
|
||||
|
|
|
@ -58,8 +58,7 @@ struct nfs_client {
|
|||
struct nfs_subversion * cl_nfs_mod; /* pointer to nfs version module */
|
||||
|
||||
u32 cl_minorversion;/* NFSv4 minorversion */
|
||||
struct rpc_cred *cl_machine_cred;
|
||||
struct rpc_cred *cl_root_cred; /* Use when machine_cred is ineffective */
|
||||
const char * cl_principal; /* used for machine cred */
|
||||
|
||||
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||
struct list_head cl_ds_clients; /* auth flavor data servers */
|
||||
|
|
|
@ -75,6 +75,8 @@ struct rpc_cred {
|
|||
#define RPCAUTH_CRED_HASHED 2
|
||||
#define RPCAUTH_CRED_NEGATIVE 3
|
||||
|
||||
struct rpc_cred *rpc_machine_cred(void);
|
||||
|
||||
/* rpc_auth au_flags */
|
||||
#define RPCAUTH_AUTH_NO_CRKEY_TIMEOUT 0x0001 /* underlying cred has no key timeout */
|
||||
|
||||
|
@ -170,7 +172,6 @@ void rpc_destroy_authunix(void);
|
|||
struct rpc_cred * rpc_lookup_cred(void);
|
||||
struct rpc_cred * rpc_lookup_cred_nonblock(void);
|
||||
struct rpc_cred * rpc_lookup_generic_cred(struct auth_cred *, int, gfp_t);
|
||||
struct rpc_cred * rpc_lookup_machine_cred(const char *service_name);
|
||||
int rpcauth_register(const struct rpc_authops *);
|
||||
int rpcauth_unregister(const struct rpc_authops *);
|
||||
struct rpc_auth * rpcauth_create(const struct rpc_auth_create_args *,
|
||||
|
|
|
@ -66,6 +66,7 @@ struct rpc_clnt {
|
|||
struct rpc_rtt cl_rtt_default;
|
||||
struct rpc_timeout cl_timeout_default;
|
||||
const struct rpc_program *cl_program;
|
||||
const char * cl_principal; /* use for machine cred */
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
struct dentry *cl_debugfs; /* debugfs directory */
|
||||
#endif
|
||||
|
|
|
@ -39,6 +39,20 @@ static const struct rpc_authops __rcu *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
|
|||
static LIST_HEAD(cred_unused);
|
||||
static unsigned long number_cred_unused;
|
||||
|
||||
static struct rpc_cred machine_cred = {
|
||||
.cr_count = REFCOUNT_INIT(1),
|
||||
};
|
||||
|
||||
/*
|
||||
* Return the machine_cred pointer to be used whenever
|
||||
* the a generic machine credential is needed.
|
||||
*/
|
||||
struct rpc_cred *rpc_machine_cred(void)
|
||||
{
|
||||
return &machine_cred;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_machine_cred);
|
||||
|
||||
#define MAX_HASHTABLE_BITS (14)
|
||||
static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
|
@ -702,6 +716,22 @@ rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct rpc_cred *
|
||||
rpcauth_bind_machine_cred(struct rpc_task *task, int lookupflags)
|
||||
{
|
||||
struct rpc_auth *auth = task->tk_client->cl_auth;
|
||||
struct auth_cred acred = {
|
||||
.principal = task->tk_client->cl_principal,
|
||||
.cred = init_task.cred,
|
||||
};
|
||||
|
||||
if (!acred.principal)
|
||||
return NULL;
|
||||
dprintk("RPC: %5u looking up %s machine cred\n",
|
||||
task->tk_pid, task->tk_client->cl_auth->au_ops->au_name);
|
||||
return auth->au_ops->lookup_cred(auth, &acred, lookupflags);
|
||||
}
|
||||
|
||||
static struct rpc_cred *
|
||||
rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags)
|
||||
{
|
||||
|
@ -716,14 +746,20 @@ static int
|
|||
rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags)
|
||||
{
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
struct rpc_cred *new;
|
||||
struct rpc_cred *new = NULL;
|
||||
int lookupflags = 0;
|
||||
|
||||
if (flags & RPC_TASK_ASYNC)
|
||||
lookupflags |= RPCAUTH_LOOKUP_NEW;
|
||||
if (cred != NULL)
|
||||
if (cred != NULL && cred != &machine_cred)
|
||||
new = cred->cr_ops->crbind(task, cred, lookupflags);
|
||||
else if (flags & RPC_TASK_ROOTCREDS)
|
||||
else if (cred == &machine_cred)
|
||||
new = rpcauth_bind_machine_cred(task, lookupflags);
|
||||
|
||||
/* If machine cred couldn't be bound, try a root cred */
|
||||
if (new)
|
||||
;
|
||||
else if (cred == &machine_cred || (flags & RPC_TASK_ROOTCREDS))
|
||||
new = rpcauth_bind_root_cred(task, lookupflags);
|
||||
else
|
||||
new = rpcauth_bind_new_cred(task, lookupflags);
|
||||
|
|
|
@ -48,27 +48,6 @@ struct rpc_cred *rpc_lookup_cred_nonblock(void)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_lookup_cred_nonblock);
|
||||
|
||||
/*
|
||||
* Public call interface for looking up machine creds.
|
||||
* Note that if service_name is NULL, we actually look up
|
||||
* "root" credential.
|
||||
*/
|
||||
struct rpc_cred *rpc_lookup_machine_cred(const char *service_name)
|
||||
{
|
||||
struct auth_cred acred = {
|
||||
.principal = service_name,
|
||||
.cred = get_task_cred(&init_task),
|
||||
};
|
||||
struct rpc_cred *ret;
|
||||
|
||||
dprintk("RPC: looking up machine cred for service %s\n",
|
||||
service_name);
|
||||
ret = generic_auth.au_ops->lookup_cred(&generic_auth, &acred, 0);
|
||||
put_cred(acred.cred);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred);
|
||||
|
||||
static struct rpc_cred *generic_bind_cred(struct rpc_task *task,
|
||||
struct rpc_cred *cred, int lookupflags)
|
||||
{
|
||||
|
|
|
@ -627,6 +627,7 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
|
|||
new->cl_noretranstimeo = clnt->cl_noretranstimeo;
|
||||
new->cl_discrtry = clnt->cl_discrtry;
|
||||
new->cl_chatty = clnt->cl_chatty;
|
||||
new->cl_principal = clnt->cl_principal;
|
||||
return new;
|
||||
|
||||
out_err:
|
||||
|
|
Loading…
Reference in New Issue