linux/net/sunrpc/auth_unix.c
<<
>>
Prefs
   1/*
   2 * linux/net/sunrpc/auth_unix.c
   3 *
   4 * UNIX-style authentication; no AUTH_SHORT support
   5 *
   6 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
   7 */
   8
   9#include <linux/slab.h>
  10#include <linux/types.h>
  11#include <linux/sched.h>
  12#include <linux/module.h>
  13#include <linux/sunrpc/clnt.h>
  14#include <linux/sunrpc/auth.h>
  15#include <linux/user_namespace.h>
  16
  17#define NFS_NGROUPS     16
  18
  19struct unx_cred {
  20        struct rpc_cred         uc_base;
  21        kgid_t                  uc_gid;
  22        kgid_t                  uc_gids[NFS_NGROUPS];
  23};
  24#define uc_uid                  uc_base.cr_uid
  25
  26#define UNX_WRITESLACK          (21 + (UNX_MAXNODENAME >> 2))
  27
  28#ifdef RPC_DEBUG
  29# define RPCDBG_FACILITY        RPCDBG_AUTH
  30#endif
  31
  32static struct rpc_auth          unix_auth;
  33static const struct rpc_credops unix_credops;
  34
  35static struct rpc_auth *
  36unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
  37{
  38        dprintk("RPC:       creating UNIX authenticator for client %p\n",
  39                        clnt);
  40        atomic_inc(&unix_auth.au_count);
  41        return &unix_auth;
  42}
  43
  44static void
  45unx_destroy(struct rpc_auth *auth)
  46{
  47        dprintk("RPC:       destroying UNIX authenticator %p\n", auth);
  48        rpcauth_clear_credcache(auth->au_credcache);
  49}
  50
  51/*
  52 * Lookup AUTH_UNIX creds for current process
  53 */
  54static struct rpc_cred *
  55unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
  56{
  57        return rpcauth_lookup_credcache(auth, acred, flags);
  58}
  59
  60static struct rpc_cred *
  61unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
  62{
  63        struct unx_cred *cred;
  64        unsigned int groups = 0;
  65        unsigned int i;
  66
  67        dprintk("RPC:       allocating UNIX cred for uid %d gid %d\n",
  68                        from_kuid(&init_user_ns, acred->uid),
  69                        from_kgid(&init_user_ns, acred->gid));
  70
  71        if (!(cred = kmalloc(sizeof(*cred), GFP_NOFS)))
  72                return ERR_PTR(-ENOMEM);
  73
  74        rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops);
  75        cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
  76
  77        if (acred->group_info != NULL)
  78                groups = acred->group_info->ngroups;
  79        if (groups > NFS_NGROUPS)
  80                groups = NFS_NGROUPS;
  81
  82        cred->uc_gid = acred->gid;
  83        for (i = 0; i < groups; i++)
  84                cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
  85        if (i < NFS_NGROUPS)
  86                cred->uc_gids[i] = INVALID_GID;
  87
  88        return &cred->uc_base;
  89}
  90
  91static void
  92unx_free_cred(struct unx_cred *unx_cred)
  93{
  94        dprintk("RPC:       unx_free_cred %p\n", unx_cred);
  95        kfree(unx_cred);
  96}
  97
  98static void
  99unx_free_cred_callback(struct rcu_head *head)
 100{
 101        struct unx_cred *unx_cred = container_of(head, struct unx_cred, uc_base.cr_rcu);
 102        unx_free_cred(unx_cred);
 103}
 104
 105static void
 106unx_destroy_cred(struct rpc_cred *cred)
 107{
 108        call_rcu(&cred->cr_rcu, unx_free_cred_callback);
 109}
 110
 111/*
 112 * Match credentials against current process creds.
 113 * The root_override argument takes care of cases where the caller may
 114 * request root creds (e.g. for NFS swapping).
 115 */
 116static int
 117unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
 118{
 119        struct unx_cred *cred = container_of(rcred, struct unx_cred, uc_base);
 120        unsigned int groups = 0;
 121        unsigned int i;
 122
 123
 124        if (!uid_eq(cred->uc_uid, acred->uid) || !gid_eq(cred->uc_gid, acred->gid))
 125                return 0;
 126
 127        if (acred->group_info != NULL)
 128                groups = acred->group_info->ngroups;
 129        if (groups > NFS_NGROUPS)
 130                groups = NFS_NGROUPS;
 131        for (i = 0; i < groups ; i++)
 132                if (!gid_eq(cred->uc_gids[i], GROUP_AT(acred->group_info, i)))
 133                        return 0;
 134        if (groups < NFS_NGROUPS && gid_valid(cred->uc_gids[groups]))
 135                return 0;
 136        return 1;
 137}
 138
 139/*
 140 * Marshal credentials.
 141 * Maybe we should keep a cached credential for performance reasons.
 142 */
 143static __be32 *
 144unx_marshal(struct rpc_task *task, __be32 *p)
 145{
 146        struct rpc_clnt *clnt = task->tk_client;
 147        struct unx_cred *cred = container_of(task->tk_rqstp->rq_cred, struct unx_cred, uc_base);
 148        __be32          *base, *hold;
 149        int             i;
 150
 151        *p++ = htonl(RPC_AUTH_UNIX);
 152        base = p++;
 153        *p++ = htonl(jiffies/HZ);
 154
 155        /*
 156         * Copy the UTS nodename captured when the client was created.
 157         */
 158        p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
 159
 160        *p++ = htonl((u32) from_kuid(&init_user_ns, cred->uc_uid));
 161        *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gid));
 162        hold = p++;
 163        for (i = 0; i < 16 && gid_valid(cred->uc_gids[i]); i++)
 164                *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gids[i]));
 165        *hold = htonl(p - hold - 1);            /* gid array length */
 166        *base = htonl((p - base - 1) << 2);     /* cred length */
 167
 168        *p++ = htonl(RPC_AUTH_NULL);
 169        *p++ = htonl(0);
 170
 171        return p;
 172}
 173
 174/*
 175 * Refresh credentials. This is a no-op for AUTH_UNIX
 176 */
 177static int
 178unx_refresh(struct rpc_task *task)
 179{
 180        set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags);
 181        return 0;
 182}
 183
 184static __be32 *
 185unx_validate(struct rpc_task *task, __be32 *p)
 186{
 187        rpc_authflavor_t        flavor;
 188        u32                     size;
 189
 190        flavor = ntohl(*p++);
 191        if (flavor != RPC_AUTH_NULL &&
 192            flavor != RPC_AUTH_UNIX &&
 193            flavor != RPC_AUTH_SHORT) {
 194                printk("RPC: bad verf flavor: %u\n", flavor);
 195                return NULL;
 196        }
 197
 198        size = ntohl(*p++);
 199        if (size > RPC_MAX_AUTH_SIZE) {
 200                printk("RPC: giant verf size: %u\n", size);
 201                return NULL;
 202        }
 203        task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2;
 204        p += (size >> 2);
 205
 206        return p;
 207}
 208
 209int __init rpc_init_authunix(void)
 210{
 211        return rpcauth_init_credcache(&unix_auth);
 212}
 213
 214void rpc_destroy_authunix(void)
 215{
 216        rpcauth_destroy_credcache(&unix_auth);
 217}
 218
 219const struct rpc_authops authunix_ops = {
 220        .owner          = THIS_MODULE,
 221        .au_flavor      = RPC_AUTH_UNIX,
 222        .au_name        = "UNIX",
 223        .create         = unx_create,
 224        .destroy        = unx_destroy,
 225        .lookup_cred    = unx_lookup_cred,
 226        .crcreate       = unx_create_cred,
 227};
 228
 229static
 230struct rpc_auth         unix_auth = {
 231        .au_cslack      = UNX_WRITESLACK,
 232        .au_rslack      = 2,                    /* assume AUTH_NULL verf */
 233        .au_ops         = &authunix_ops,
 234        .au_flavor      = RPC_AUTH_UNIX,
 235        .au_count       = ATOMIC_INIT(0),
 236};
 237
 238static
 239const struct rpc_credops unix_credops = {
 240        .cr_name        = "AUTH_UNIX",
 241        .crdestroy      = unx_destroy_cred,
 242        .crbind         = rpcauth_generic_bind_cred,
 243        .crmatch        = unx_match,
 244        .crmarshal      = unx_marshal,
 245        .crrefresh      = unx_refresh,
 246        .crvalidate     = unx_validate,
 247};
 248