nfsd: pass client principal name in rsc downcall
authorOlga Kornievskaia <aglo@citi.umich.edu>
Tue, 23 Dec 2008 21:17:15 +0000 (16:17 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 23 Dec 2008 21:17:15 +0000 (16:17 -0500)
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>
fs/nfsd/nfs4state.c
include/linux/nfsd/state.h
include/linux/sunrpc/svcauth_gss.h
net/sunrpc/auth_gss/svcauth_gss.c

index 1a052ac2bde90b6599194380124c61b1c4054134..f3b9a8d064f353383d94f68c287d7fad7d484804 100644 (file)
@@ -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 @@ free_client(struct nfs4_client *clp)
        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 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        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 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        }
        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);
index d0fe2e378452bfb0050b559e58769870b8ce0de4..ce7cbf4b7c930d543b2b9bf2e423615746ea15f8 100644 (file)
@@ -124,6 +124,7 @@ struct nfs4_client {
        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 */
index c9165d9771a800b5d2df9053a777cc2ca30468e2..ca7d725861fc0e885e396d50a5df9b895c7465ef 100644 (file)
@@ -20,6 +20,7 @@ int gss_svc_init(void);
 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 */
index 12803da95dc4c6c3fed98d2dfa70d2335135f03d..e9baa6ebb1dd2ed5ec445792ee3fa5c98e920247 100644 (file)
@@ -332,6 +332,7 @@ struct rsc {
        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 @@ static void rsc_free(struct rsc *rsci)
                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 @@ rsc_init(struct cache_head *cnew, struct cache_head *ctmp)
        tmp->handle.data = NULL;
        new->mechctx = NULL;
        new->cred.cr_group_info = NULL;
+       new->client_name = NULL;
 }
 
 static void
@@ -397,6 +400,8 @@ update_rsc(struct cache_head *cnew, struct cache_head *ctmp)
        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 @@ static int rsc_parse(struct cache_detail *cd,
                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 gss_svc_data {
        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)
 {