nfsd: pass client principal name in rsc downcall
Two principals are involved in krb5 authentication: the target, who we
authenticate *to* (normally the name of the server, like
nfs/server.citi.umich.edu@CITI.UMICH.EDU), and the source, we we
authenticate *as* (normally a user, like bfields@UMICH.EDU)
In the case of NFSv4 callbacks, the target of the callback should be the
source of the client's setclientid call, and the source should be the
nfs server's own principal.
Therefore we allow svcgssd to pass down the name of the principal that
just authenticated, so that on setclientid we can store that principal
name with the new client, to be used later on callbacks.
Signed-off-by: Olga Kornievskaia <aglo@citi.umich.edu>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 1a052ac2..f3b9a8d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -54,6 +54,7 @@
#include <linux/mutex.h>
#include <linux/lockd/bind.h>
#include <linux/module.h>
+#include <linux/sunrpc/svcauth_gss.h>
#define NFSDDBG_FACILITY NFSDDBG_PROC
@@ -377,6 +378,7 @@
shutdown_callback_client(clp);
if (clp->cl_cred.cr_group_info)
put_group_info(clp->cl_cred.cr_group_info);
+ kfree(clp->cl_principal);
kfree(clp->cl_name.data);
kfree(clp);
}
@@ -696,6 +698,7 @@
unsigned int strhashval;
struct nfs4_client *conf, *unconf, *new;
__be32 status;
+ char *princ;
char dname[HEXDIR_LEN];
if (!check_name(clname))
@@ -783,6 +786,14 @@
}
copy_verf(new, &clverifier);
new->cl_addr = sin->sin_addr.s_addr;
+ princ = svc_gss_principal(rqstp);
+ if (princ) {
+ new->cl_principal = kstrdup(princ, GFP_KERNEL);
+ if (new->cl_principal == NULL) {
+ free_client(new);
+ goto out;
+ }
+ }
copy_cred(&new->cl_cred, &rqstp->rq_cred);
gen_confirm(new);
gen_callback(new, setclid);
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index d0fe2e3..ce7cbf4 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -124,6 +124,7 @@
nfs4_verifier cl_verifier; /* generated by client */
time_t cl_time; /* time of last lease renewal */
__be32 cl_addr; /* client ipaddress */
+ char *cl_principal; /* setclientid principal name */
struct svc_cred cl_cred; /* setclientid principal */
clientid_t cl_clientid; /* generated by server */
nfs4_verifier cl_confirm; /* generated by server */
diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h
index c9165d9..ca7d725 100644
--- a/include/linux/sunrpc/svcauth_gss.h
+++ b/include/linux/sunrpc/svcauth_gss.h
@@ -20,6 +20,7 @@
void gss_svc_shutdown(void);
int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
u32 svcauth_gss_flavor(struct auth_domain *dom);
+char *svc_gss_principal(struct svc_rqst *);
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 12803da..e9baa6e 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -332,6 +332,7 @@
struct svc_cred cred;
struct gss_svc_seq_data seqdata;
struct gss_ctx *mechctx;
+ char *client_name;
};
static struct cache_head *rsc_table[RSC_HASHMAX];
@@ -346,6 +347,7 @@
gss_delete_sec_context(&rsci->mechctx);
if (rsci->cred.cr_group_info)
put_group_info(rsci->cred.cr_group_info);
+ kfree(rsci->client_name);
}
static void rsc_put(struct kref *ref)
@@ -383,6 +385,7 @@
tmp->handle.data = NULL;
new->mechctx = NULL;
new->cred.cr_group_info = NULL;
+ new->client_name = NULL;
}
static void
@@ -397,6 +400,8 @@
spin_lock_init(&new->seqdata.sd_lock);
new->cred = tmp->cred;
tmp->cred.cr_group_info = NULL;
+ new->client_name = tmp->client_name;
+ tmp->client_name = NULL;
}
static struct cache_head *
@@ -486,6 +491,15 @@
status = gss_import_sec_context(buf, len, gm, &rsci.mechctx);
if (status)
goto out;
+
+ /* get client name */
+ len = qword_get(&mesg, buf, mlen);
+ if (len > 0) {
+ rsci.client_name = kstrdup(buf, GFP_KERNEL);
+ if (!rsci.client_name)
+ goto out;
+ }
+
}
rsci.h.expiry_time = expiry;
rscp = rsc_update(&rsci, rscp);
@@ -913,6 +927,15 @@
struct rsc *rsci;
};
+char *svc_gss_principal(struct svc_rqst *rqstp)
+{
+ struct gss_svc_data *gd = (struct gss_svc_data *)rqstp->rq_auth_data;
+
+ if (gd && gd->rsci)
+ return gd->rsci->client_name;
+ return NULL;
+}
+
static int
svcauth_gss_set_client(struct svc_rqst *rqstp)
{