fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / sunrpc / auth_unix.c
index edbe8f8..97b991c 100644 (file)
@@ -9,18 +9,16 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/module.h>
-#include <linux/socket.h>
-#include <linux/in.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/auth.h>
+#include <linux/vs_tag.h>
 
 #define NFS_NGROUPS    16
 
 struct unx_cred {
        struct rpc_cred         uc_base;
        gid_t                   uc_gid;
-       uid_t                   uc_puid;                /* process uid */
-       gid_t                   uc_pgid;                /* process gid */
+       tag_t                   uc_tag;
        gid_t                   uc_gids[NFS_NGROUPS];
 };
 #define uc_uid                 uc_base.cr_uid
@@ -36,24 +34,17 @@ struct unx_cred {
 # define RPCDBG_FACILITY       RPCDBG_AUTH
 #endif
 
+static struct rpc_auth         unix_auth;
+static struct rpc_cred_cache   unix_cred_cache;
 static struct rpc_credops      unix_credops;
 
 static struct rpc_auth *
 unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
 {
-       struct rpc_auth *auth;
-
        dprintk("RPC: creating UNIX authenticator for client %p\n", clnt);
-       if (!(auth = (struct rpc_auth *) kmalloc(sizeof(*auth), GFP_KERNEL)))
-               return NULL;
-       auth->au_cslack = UNX_WRITESLACK;
-       auth->au_rslack = 2;    /* assume AUTH_NULL verf */
-       auth->au_expire = UNX_CRED_EXPIRE;
-       auth->au_ops = &authunix_ops;
-
-       rpcauth_init_credcache(auth);
-
-       return auth;
+       if (atomic_inc_return(&unix_auth.au_count) == 0)
+               unix_cred_cache.nextgc = jiffies + (unix_cred_cache.expire >> 1);
+       return &unix_auth;
 }
 
 static void
@@ -63,6 +54,15 @@ unx_destroy(struct rpc_auth *auth)
        rpcauth_free_credcache(auth);
 }
 
+/*
+ * Lookup AUTH_UNIX creds for current process
+ */
+static struct rpc_cred *
+unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
+{
+       return rpcauth_lookup_credcache(auth, acred, flags);
+}
+
 static struct rpc_cred *
 unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 {
@@ -72,14 +72,15 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
        dprintk("RPC:      allocating UNIX cred for uid %d gid %d\n",
                                acred->uid, acred->gid);
 
-       if (!(cred = (struct unx_cred *) kmalloc(sizeof(*cred), GFP_KERNEL)))
-               return NULL;
+       if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL)))
+               return ERR_PTR(-ENOMEM);
 
-       atomic_set(&cred->uc_count, 0);
+       atomic_set(&cred->uc_count, 1);
        cred->uc_flags = RPCAUTH_CRED_UPTODATE;
-       if (flags & RPC_TASK_ROOTCREDS) {
-               cred->uc_uid = cred->uc_puid = 0;
-               cred->uc_gid = cred->uc_pgid = 0;
+       if (flags & RPCAUTH_LOOKUP_ROOTCREDS) {
+               cred->uc_uid = 0;
+               cred->uc_gid = 0;
+               cred->uc_tag = dx_current_tag();
                cred->uc_gids[0] = NOGROUP;
        } else {
                int groups = acred->group_info->ngroups;
@@ -88,8 +89,7 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 
                cred->uc_uid = acred->uid;
                cred->uc_gid = acred->gid;
-               cred->uc_puid = current->uid;
-               cred->uc_pgid = current->gid;
+               cred->uc_tag = acred->tag;
                for (i = 0; i < groups; i++)
                        cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
                if (i < NFS_NGROUPS)
@@ -112,18 +112,17 @@ unx_destroy_cred(struct rpc_cred *cred)
  * request root creds (e.g. for NFS swapping).
  */
 static int
-unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags)
+unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
 {
        struct unx_cred *cred = (struct unx_cred *) rcred;
        int             i;
 
-       if (!(taskflags & RPC_TASK_ROOTCREDS)) {
+       if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) {
                int groups;
 
                if (cred->uc_uid != acred->uid
                 || cred->uc_gid != acred->gid
-                || cred->uc_puid != current->uid
-                || cred->uc_pgid != current->gid)
+                || cred->uc_tag != acred->tag)
                        return 0;
 
                groups = acred->group_info->ngroups;
@@ -134,8 +133,8 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags)
                                return 0;
                return 1;
        }
-       return (cred->uc_uid == 0 && cred->uc_puid == 0
-            && cred->uc_gid == 0 && cred->uc_pgid == 0
+       return (cred->uc_uid == 0
+            && cred->uc_gid == 0
             && cred->uc_gids[0] == (gid_t) NOGROUP);
 }
 
@@ -143,13 +142,13 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags)
  * Marshal credentials.
  * Maybe we should keep a cached credential for performance reasons.
  */
-static u32 *
-unx_marshal(struct rpc_task *task, u32 *p, int ruid)
+static __be32 *
+unx_marshal(struct rpc_task *task, __be32 *p)
 {
        struct rpc_clnt *clnt = task->tk_client;
        struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred;
-       u32             *base, *hold;
-       int             i;
+       __be32          *base, *hold;
+       int             i, tag;
 
        *p++ = htonl(RPC_AUTH_UNIX);
        base = p++;
@@ -159,15 +158,12 @@ unx_marshal(struct rpc_task *task, u32 *p, int ruid)
         * Copy the UTS nodename captured when the client was created.
         */
        p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
+       tag = task->tk_client->cl_tag;
 
-       /* Note: we don't use real uid if it involves raising privilege */
-       if (ruid && cred->uc_puid != 0 && cred->uc_pgid != 0) {
-               *p++ = htonl((u32) cred->uc_puid);
-               *p++ = htonl((u32) cred->uc_pgid);
-       } else {
-               *p++ = htonl((u32) cred->uc_uid);
-               *p++ = htonl((u32) cred->uc_gid);
-       }
+       *p++ = htonl((u32) TAGINO_UID(tag,
+               cred->uc_uid, cred->uc_tag));
+       *p++ = htonl((u32) TAGINO_GID(tag,
+               cred->uc_gid, cred->uc_tag));
        hold = p++;
        for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++)
                *p++ = htonl((u32) cred->uc_gids[i]);
@@ -187,11 +183,11 @@ static int
 unx_refresh(struct rpc_task *task)
 {
        task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
-       return task->tk_status = -EACCES;
+       return 0;
 }
 
-static u32 *
-unx_validate(struct rpc_task *task, u32 *p)
+static __be32 *
+unx_validate(struct rpc_task *task, __be32 *p)
 {
        rpc_authflavor_t        flavor;
        u32                     size;
@@ -223,11 +219,28 @@ struct rpc_authops        authunix_ops = {
 #endif
        .create         = unx_create,
        .destroy        = unx_destroy,
+       .lookup_cred    = unx_lookup_cred,
        .crcreate       = unx_create_cred,
 };
 
+static
+struct rpc_cred_cache  unix_cred_cache = {
+       .expire         = UNX_CRED_EXPIRE,
+};
+
+static
+struct rpc_auth                unix_auth = {
+       .au_cslack      = UNX_WRITESLACK,
+       .au_rslack      = 2,                    /* assume AUTH_NULL verf */
+       .au_ops         = &authunix_ops,
+       .au_flavor      = RPC_AUTH_UNIX,
+       .au_count       = ATOMIC_INIT(0),
+       .au_credcache   = &unix_cred_cache,
+};
+
 static
 struct rpc_credops     unix_credops = {
+       .cr_name        = "AUTH_UNIX",
        .crdestroy      = unx_destroy_cred,
        .crmatch        = unx_match,
        .crmarshal      = unx_marshal,