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        refcount_inc(&unix_auth.au_count);
  32        return &unix_auth;
  33}
  34
  35static void
  36unx_destroy(struct rpc_auth *auth)
  37{
  38}
  39
  40/*
  41 * Lookup AUTH_UNIX creds for current process
  42 */
  43static struct rpc_cred *
  44unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
  45{
  46        struct rpc_cred *ret = mempool_alloc(unix_pool, GFP_NOFS);
  47
  48        rpcauth_init_cred(ret, acred, auth, &unix_credops);
  49        ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
  50        return ret;
  51}
  52
  53static void
  54unx_free_cred_callback(struct rcu_head *head)
  55{
  56        struct rpc_cred *rpc_cred = container_of(head, struct rpc_cred, cr_rcu);
  57
  58        put_cred(rpc_cred->cr_cred);
  59        mempool_free(rpc_cred, unix_pool);
  60}
  61
  62static void
  63unx_destroy_cred(struct rpc_cred *cred)
  64{
  65        call_rcu(&cred->cr_rcu, unx_free_cred_callback);
  66}
  67
  68/*
  69 * Match credentials against current the auth_cred.
  70 */
  71static int
  72unx_match(struct auth_cred *acred, struct rpc_cred *cred, int flags)
  73{
  74        unsigned int groups = 0;
  75        unsigned int i;
  76
  77        if (cred->cr_cred == acred->cred)
  78                return 1;
  79
  80        if (!uid_eq(cred->cr_cred->fsuid, acred->cred->fsuid) || !gid_eq(cred->cr_cred->fsgid, acred->cred->fsgid))
  81                return 0;
  82
  83        if (acred->cred->group_info != NULL)
  84                groups = acred->cred->group_info->ngroups;
  85        if (groups > UNX_NGROUPS)
  86                groups = UNX_NGROUPS;
  87        if (cred->cr_cred->group_info == NULL)
  88                return groups == 0;
  89        if (groups != cred->cr_cred->group_info->ngroups)
  90                return 0;
  91
  92        for (i = 0; i < groups ; i++)
  93                if (!gid_eq(cred->cr_cred->group_info->gid[i], acred->cred->group_info->gid[i]))
  94                        return 0;
  95        return 1;
  96}
  97
  98/*
  99 * Marshal credentials.
 100 * Maybe we should keep a cached credential for performance reasons.
 101 */
 102static int
 103unx_marshal(struct rpc_task *task, struct xdr_stream *xdr)
 104{
 105        struct rpc_clnt *clnt = task->tk_client;
 106        struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 107        __be32          *p, *cred_len, *gidarr_len;
 108        int             i;
 109        struct group_info *gi = cred->cr_cred->group_info;
 110        struct user_namespace *userns = clnt->cl_cred ?
 111                clnt->cl_cred->user_ns : &init_user_ns;
 112
 113        /* Credential */
 114
 115        p = xdr_reserve_space(xdr, 3 * sizeof(*p));
 116        if (!p)
 117                goto marshal_failed;
 118        *p++ = rpc_auth_unix;
 119        cred_len = p++;
 120        *p++ = xdr_zero;        /* stamp */
 121        if (xdr_stream_encode_opaque(xdr, clnt->cl_nodename,
 122                                     clnt->cl_nodelen) < 0)
 123                goto marshal_failed;
 124        p = xdr_reserve_space(xdr, 3 * sizeof(*p));
 125        if (!p)
 126                goto marshal_failed;
 127        *p++ = cpu_to_be32(from_kuid_munged(userns, cred->cr_cred->fsuid));
 128        *p++ = cpu_to_be32(from_kgid_munged(userns, cred->cr_cred->fsgid));
 129
 130        gidarr_len = p++;
 131        if (gi)
 132                for (i = 0; i < UNX_NGROUPS && i < gi->ngroups; i++)
 133                        *p++ = cpu_to_be32(from_kgid_munged(userns, gi->gid[i]));
 134        *gidarr_len = cpu_to_be32(p - gidarr_len - 1);
 135        *cred_len = cpu_to_be32((p - cred_len - 1) << 2);
 136        p = xdr_reserve_space(xdr, (p - gidarr_len - 1) << 2);
 137        if (!p)
 138                goto marshal_failed;
 139
 140        /* Verifier */
 141
 142        p = xdr_reserve_space(xdr, 2 * sizeof(*p));
 143        if (!p)
 144                goto marshal_failed;
 145        *p++ = rpc_auth_null;
 146        *p   = xdr_zero;
 147
 148        return 0;
 149
 150marshal_failed:
 151        return -EMSGSIZE;
 152}
 153
 154/*
 155 * Refresh credentials. This is a no-op for AUTH_UNIX
 156 */
 157static int
 158unx_refresh(struct rpc_task *task)
 159{
 160        set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags);
 161        return 0;
 162}
 163
 164static int
 165unx_validate(struct rpc_task *task, struct xdr_stream *xdr)
 166{
 167        struct rpc_auth *auth = task->tk_rqstp->rq_cred->cr_auth;
 168        __be32 *p;
 169        u32 size;
 170
 171        p = xdr_inline_decode(xdr, 2 * sizeof(*p));
 172        if (!p)
 173                return -EIO;
 174        switch (*p++) {
 175        case rpc_auth_null:
 176        case rpc_auth_unix:
 177        case rpc_auth_short:
 178                break;
 179        default:
 180                return -EIO;
 181        }
 182        size = be32_to_cpup(p);
 183        if (size > RPC_MAX_AUTH_SIZE)
 184                return -EIO;
 185        p = xdr_inline_decode(xdr, size);
 186        if (!p)
 187                return -EIO;
 188
 189        auth->au_verfsize = XDR_QUADLEN(size) + 2;
 190        auth->au_rslack = XDR_QUADLEN(size) + 2;
 191        auth->au_ralign = XDR_QUADLEN(size) + 2;
 192        return 0;
 193}
 194
 195int __init rpc_init_authunix(void)
 196{
 197        unix_pool = mempool_create_kmalloc_pool(16, sizeof(struct rpc_cred));
 198        return unix_pool ? 0 : -ENOMEM;
 199}
 200
 201void rpc_destroy_authunix(void)
 202{
 203        mempool_destroy(unix_pool);
 204}
 205
 206const struct rpc_authops authunix_ops = {
 207        .owner          = THIS_MODULE,
 208        .au_flavor      = RPC_AUTH_UNIX,
 209        .au_name        = "UNIX",
 210        .create         = unx_create,
 211        .destroy        = unx_destroy,
 212        .lookup_cred    = unx_lookup_cred,
 213};
 214
 215static
 216struct rpc_auth         unix_auth = {
 217        .au_cslack      = UNX_CALLSLACK,
 218        .au_rslack      = NUL_REPLYSLACK,
 219        .au_verfsize    = NUL_REPLYSLACK,
 220        .au_ops         = &authunix_ops,
 221        .au_flavor      = RPC_AUTH_UNIX,
 222        .au_count       = REFCOUNT_INIT(1),
 223};
 224
 225static
 226const struct rpc_credops unix_credops = {
 227        .cr_name        = "AUTH_UNIX",
 228        .crdestroy      = unx_destroy_cred,
 229        .crmatch        = unx_match,
 230        .crmarshal      = unx_marshal,
 231        .crwrap_req     = rpcauth_wrap_req_encode,
 232        .crrefresh      = unx_refresh,
 233        .crvalidate     = unx_validate,
 234        .crunwrap_resp  = rpcauth_unwrap_resp_decode,
 235};
 236