linux/net/sunrpc/auth_unix.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * linux/net/sunrpc/auth_unix.c
   4 *
   5 * UNIX-style authentication; no AUTH_SHORT support
   6 *
   7 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
   8 */
   9
  10#include <linux/slab.h>
  11#include <linux/types.h>
  12#include <linux/sched.h>
  13#include <linux/module.h>
  14#include <linux/mempool.h>
  15#include <linux/sunrpc/clnt.h>
  16#include <linux/sunrpc/auth.h>
  17#include <linux/user_namespace.h>
  18
  19
  20#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
  21# define RPCDBG_FACILITY        RPCDBG_AUTH
  22#endif
  23
  24static struct rpc_auth          unix_auth;
  25static const struct rpc_credops unix_credops;
  26static mempool_t                *unix_pool;
  27
  28static struct rpc_auth *
  29unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
  30{
  31        dprintk("RPC:       creating UNIX authenticator for client %p\n",
  32                        clnt);
  33        refcount_inc(&unix_auth.au_count);
  34        return &unix_auth;
  35}
  36
  37static void
  38unx_destroy(struct rpc_auth *auth)
  39{
  40        dprintk("RPC:       destroying UNIX authenticator %p\n", auth);
  41}
  42
  43/*
  44 * Lookup AUTH_UNIX creds for current process
  45 */
  46static struct rpc_cred *
  47unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
  48{
  49        struct rpc_cred *ret = mempool_alloc(unix_pool, GFP_NOFS);
  50
  51        dprintk("RPC:       allocating UNIX cred for uid %d gid %d\n",
  52                        from_kuid(&init_user_ns, acred->cred->fsuid),
  53                        from_kgid(&init_user_ns, acred->cred->fsgid));
  54
  55        rpcauth_init_cred(ret, acred, auth, &unix_credops);
  56        ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
  57        return ret;
  58}
  59
  60static void
  61unx_free_cred_callback(struct rcu_head *head)
  62{
  63        struct rpc_cred *rpc_cred = container_of(head, struct rpc_cred, cr_rcu);
  64        dprintk("RPC:       unx_free_cred %p\n", rpc_cred);
  65        put_cred(rpc_cred->cr_cred);
  66        mempool_free(rpc_cred, unix_pool);
  67}
  68
  69static void
  70unx_destroy_cred(struct rpc_cred *cred)
  71{
  72        call_rcu(&cred->cr_rcu, unx_free_cred_callback);
  73}
  74
  75/*
  76 * Match credentials against current the auth_cred.
  77 */
  78static int
  79unx_match(struct auth_cred *acred, struct rpc_cred *cred, int flags)
  80{
  81        unsigned int groups = 0;
  82        unsigned int i;
  83
  84        if (cred->cr_cred == acred->cred)
  85                return 1;
  86
  87        if (!uid_eq(cred->cr_cred->fsuid, acred->cred->fsuid) || !gid_eq(cred->cr_cred->fsgid, acred->cred->fsgid))
  88                return 0;
  89
  90        if (acred->cred && acred->cred->group_info != NULL)
  91                groups = acred->cred->group_info->ngroups;
  92        if (groups > UNX_NGROUPS)
  93                groups = UNX_NGROUPS;
  94        if (cred->cr_cred->group_info == NULL)
  95                return groups == 0;
  96        if (groups != cred->cr_cred->group_info->ngroups)
  97                return 0;
  98
  99        for (i = 0; i < groups ; i++)
 100                if (!gid_eq(cred->cr_cred->group_info->gid[i], acred->cred->group_info->gid[i]))
 101                        return 0;
 102        return 1;
 103}
 104
 105/*
 106 * Marshal credentials.
 107 * Maybe we should keep a cached credential for performance reasons.
 108 */
 109static __be32 *
 110unx_marshal(struct rpc_task *task, __be32 *p)
 111{
 112        struct rpc_clnt *clnt = task->tk_client;
 113        struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 114        __be32          *base, *hold;
 115        int             i;
 116        struct group_info *gi = cred->cr_cred->group_info;
 117
 118        *p++ = htonl(RPC_AUTH_UNIX);
 119        base = p++;
 120        *p++ = htonl(jiffies/HZ);
 121
 122        /*
 123         * Copy the UTS nodename captured when the client was created.
 124         */
 125        p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
 126
 127        *p++ = htonl((u32) from_kuid(&init_user_ns, cred->cr_cred->fsuid));
 128        *p++ = htonl((u32) from_kgid(&init_user_ns, cred->cr_cred->fsgid));
 129        hold = p++;
 130        if (gi)
 131                for (i = 0; i < UNX_NGROUPS && i < gi->ngroups; i++)
 132                        *p++ = htonl((u32) from_kgid(&init_user_ns, gi->gid[i]));
 133        *hold = htonl(p - hold - 1);            /* gid array length */
 134        *base = htonl((p - base - 1) << 2);     /* cred length */
 135
 136        *p++ = htonl(RPC_AUTH_NULL);
 137        *p++ = htonl(0);
 138
 139        return p;
 140}
 141
 142/*
 143 * Refresh credentials. This is a no-op for AUTH_UNIX
 144 */
 145static int
 146unx_refresh(struct rpc_task *task)
 147{
 148        set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags);
 149        return 0;
 150}
 151
 152static __be32 *
 153unx_validate(struct rpc_task *task, __be32 *p)
 154{
 155        rpc_authflavor_t        flavor;
 156        u32                     size;
 157
 158        flavor = ntohl(*p++);
 159        if (flavor != RPC_AUTH_NULL &&
 160            flavor != RPC_AUTH_UNIX &&
 161            flavor != RPC_AUTH_SHORT) {
 162                printk("RPC: bad verf flavor: %u\n", flavor);
 163                return ERR_PTR(-EIO);
 164        }
 165
 166        size = ntohl(*p++);
 167        if (size > RPC_MAX_AUTH_SIZE) {
 168                printk("RPC: giant verf size: %u\n", size);
 169                return ERR_PTR(-EIO);
 170        }
 171        task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2;
 172        p += (size >> 2);
 173
 174        return p;
 175}
 176
 177int __init rpc_init_authunix(void)
 178{
 179        unix_pool = mempool_create_kmalloc_pool(16, sizeof(struct rpc_cred));
 180        return unix_pool ? 0 : -ENOMEM;
 181}
 182
 183void rpc_destroy_authunix(void)
 184{
 185        mempool_destroy(unix_pool);
 186}
 187
 188const struct rpc_authops authunix_ops = {
 189        .owner          = THIS_MODULE,
 190        .au_flavor      = RPC_AUTH_UNIX,
 191        .au_name        = "UNIX",
 192        .create         = unx_create,
 193        .destroy        = unx_destroy,
 194        .lookup_cred    = unx_lookup_cred,
 195};
 196
 197static
 198struct rpc_auth         unix_auth = {
 199        .au_cslack      = UNX_CALLSLACK,
 200        .au_rslack      = NUL_REPLYSLACK,
 201        .au_ops         = &authunix_ops,
 202        .au_flavor      = RPC_AUTH_UNIX,
 203        .au_count       = REFCOUNT_INIT(1),
 204};
 205
 206static
 207const struct rpc_credops unix_credops = {
 208        .cr_name        = "AUTH_UNIX",
 209        .crdestroy      = unx_destroy_cred,
 210        .crmatch        = unx_match,
 211        .crmarshal      = unx_marshal,
 212        .crrefresh      = unx_refresh,
 213        .crvalidate     = unx_validate,
 214};
 215