Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * linux/net/sunrpc/auth_unix.c
0004  *
0005  * UNIX-style authentication; no AUTH_SHORT support
0006  *
0007  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
0008  */
0009 
0010 #include <linux/slab.h>
0011 #include <linux/types.h>
0012 #include <linux/sched.h>
0013 #include <linux/module.h>
0014 #include <linux/mempool.h>
0015 #include <linux/sunrpc/clnt.h>
0016 #include <linux/sunrpc/auth.h>
0017 #include <linux/user_namespace.h>
0018 
0019 
0020 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
0021 # define RPCDBG_FACILITY    RPCDBG_AUTH
0022 #endif
0023 
0024 static struct rpc_auth      unix_auth;
0025 static const struct rpc_credops unix_credops;
0026 static mempool_t        *unix_pool;
0027 
0028 static struct rpc_auth *
0029 unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
0030 {
0031     refcount_inc(&unix_auth.au_count);
0032     return &unix_auth;
0033 }
0034 
0035 static void
0036 unx_destroy(struct rpc_auth *auth)
0037 {
0038 }
0039 
0040 /*
0041  * Lookup AUTH_UNIX creds for current process
0042  */
0043 static struct rpc_cred *unx_lookup_cred(struct rpc_auth *auth,
0044                     struct auth_cred *acred, int flags)
0045 {
0046     struct rpc_cred *ret;
0047 
0048     ret = kmalloc(sizeof(*ret), rpc_task_gfp_mask());
0049     if (!ret) {
0050         if (!(flags & RPCAUTH_LOOKUP_ASYNC))
0051             return ERR_PTR(-ENOMEM);
0052         ret = mempool_alloc(unix_pool, GFP_NOWAIT);
0053         if (!ret)
0054             return ERR_PTR(-ENOMEM);
0055     }
0056     rpcauth_init_cred(ret, acred, auth, &unix_credops);
0057     ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
0058     return ret;
0059 }
0060 
0061 static void
0062 unx_free_cred_callback(struct rcu_head *head)
0063 {
0064     struct rpc_cred *rpc_cred = container_of(head, struct rpc_cred, cr_rcu);
0065 
0066     put_cred(rpc_cred->cr_cred);
0067     mempool_free(rpc_cred, unix_pool);
0068 }
0069 
0070 static void
0071 unx_destroy_cred(struct rpc_cred *cred)
0072 {
0073     call_rcu(&cred->cr_rcu, unx_free_cred_callback);
0074 }
0075 
0076 /*
0077  * Match credentials against current the auth_cred.
0078  */
0079 static int
0080 unx_match(struct auth_cred *acred, struct rpc_cred *cred, int flags)
0081 {
0082     unsigned int groups = 0;
0083     unsigned int i;
0084 
0085     if (cred->cr_cred == acred->cred)
0086         return 1;
0087 
0088     if (!uid_eq(cred->cr_cred->fsuid, acred->cred->fsuid) || !gid_eq(cred->cr_cred->fsgid, acred->cred->fsgid))
0089         return 0;
0090 
0091     if (acred->cred->group_info != NULL)
0092         groups = acred->cred->group_info->ngroups;
0093     if (groups > UNX_NGROUPS)
0094         groups = UNX_NGROUPS;
0095     if (cred->cr_cred->group_info == NULL)
0096         return groups == 0;
0097     if (groups != cred->cr_cred->group_info->ngroups)
0098         return 0;
0099 
0100     for (i = 0; i < groups ; i++)
0101         if (!gid_eq(cred->cr_cred->group_info->gid[i], acred->cred->group_info->gid[i]))
0102             return 0;
0103     return 1;
0104 }
0105 
0106 /*
0107  * Marshal credentials.
0108  * Maybe we should keep a cached credential for performance reasons.
0109  */
0110 static int
0111 unx_marshal(struct rpc_task *task, struct xdr_stream *xdr)
0112 {
0113     struct rpc_clnt *clnt = task->tk_client;
0114     struct rpc_cred *cred = task->tk_rqstp->rq_cred;
0115     __be32      *p, *cred_len, *gidarr_len;
0116     int     i;
0117     struct group_info *gi = cred->cr_cred->group_info;
0118     struct user_namespace *userns = clnt->cl_cred ?
0119         clnt->cl_cred->user_ns : &init_user_ns;
0120 
0121     /* Credential */
0122 
0123     p = xdr_reserve_space(xdr, 3 * sizeof(*p));
0124     if (!p)
0125         goto marshal_failed;
0126     *p++ = rpc_auth_unix;
0127     cred_len = p++;
0128     *p++ = xdr_zero;    /* stamp */
0129     if (xdr_stream_encode_opaque(xdr, clnt->cl_nodename,
0130                      clnt->cl_nodelen) < 0)
0131         goto marshal_failed;
0132     p = xdr_reserve_space(xdr, 3 * sizeof(*p));
0133     if (!p)
0134         goto marshal_failed;
0135     *p++ = cpu_to_be32(from_kuid_munged(userns, cred->cr_cred->fsuid));
0136     *p++ = cpu_to_be32(from_kgid_munged(userns, cred->cr_cred->fsgid));
0137 
0138     gidarr_len = p++;
0139     if (gi)
0140         for (i = 0; i < UNX_NGROUPS && i < gi->ngroups; i++)
0141             *p++ = cpu_to_be32(from_kgid_munged(userns, gi->gid[i]));
0142     *gidarr_len = cpu_to_be32(p - gidarr_len - 1);
0143     *cred_len = cpu_to_be32((p - cred_len - 1) << 2);
0144     p = xdr_reserve_space(xdr, (p - gidarr_len - 1) << 2);
0145     if (!p)
0146         goto marshal_failed;
0147 
0148     /* Verifier */
0149 
0150     p = xdr_reserve_space(xdr, 2 * sizeof(*p));
0151     if (!p)
0152         goto marshal_failed;
0153     *p++ = rpc_auth_null;
0154     *p   = xdr_zero;
0155 
0156     return 0;
0157 
0158 marshal_failed:
0159     return -EMSGSIZE;
0160 }
0161 
0162 /*
0163  * Refresh credentials. This is a no-op for AUTH_UNIX
0164  */
0165 static int
0166 unx_refresh(struct rpc_task *task)
0167 {
0168     set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags);
0169     return 0;
0170 }
0171 
0172 static int
0173 unx_validate(struct rpc_task *task, struct xdr_stream *xdr)
0174 {
0175     struct rpc_auth *auth = task->tk_rqstp->rq_cred->cr_auth;
0176     __be32 *p;
0177     u32 size;
0178 
0179     p = xdr_inline_decode(xdr, 2 * sizeof(*p));
0180     if (!p)
0181         return -EIO;
0182     switch (*p++) {
0183     case rpc_auth_null:
0184     case rpc_auth_unix:
0185     case rpc_auth_short:
0186         break;
0187     default:
0188         return -EIO;
0189     }
0190     size = be32_to_cpup(p);
0191     if (size > RPC_MAX_AUTH_SIZE)
0192         return -EIO;
0193     p = xdr_inline_decode(xdr, size);
0194     if (!p)
0195         return -EIO;
0196 
0197     auth->au_verfsize = XDR_QUADLEN(size) + 2;
0198     auth->au_rslack = XDR_QUADLEN(size) + 2;
0199     auth->au_ralign = XDR_QUADLEN(size) + 2;
0200     return 0;
0201 }
0202 
0203 int __init rpc_init_authunix(void)
0204 {
0205     unix_pool = mempool_create_kmalloc_pool(16, sizeof(struct rpc_cred));
0206     return unix_pool ? 0 : -ENOMEM;
0207 }
0208 
0209 void rpc_destroy_authunix(void)
0210 {
0211     mempool_destroy(unix_pool);
0212 }
0213 
0214 const struct rpc_authops authunix_ops = {
0215     .owner      = THIS_MODULE,
0216     .au_flavor  = RPC_AUTH_UNIX,
0217     .au_name    = "UNIX",
0218     .create     = unx_create,
0219     .destroy    = unx_destroy,
0220     .lookup_cred    = unx_lookup_cred,
0221 };
0222 
0223 static
0224 struct rpc_auth     unix_auth = {
0225     .au_cslack  = UNX_CALLSLACK,
0226     .au_rslack  = NUL_REPLYSLACK,
0227     .au_verfsize    = NUL_REPLYSLACK,
0228     .au_ops     = &authunix_ops,
0229     .au_flavor  = RPC_AUTH_UNIX,
0230     .au_count   = REFCOUNT_INIT(1),
0231 };
0232 
0233 static
0234 const struct rpc_credops unix_credops = {
0235     .cr_name    = "AUTH_UNIX",
0236     .crdestroy  = unx_destroy_cred,
0237     .crmatch    = unx_match,
0238     .crmarshal  = unx_marshal,
0239     .crwrap_req = rpcauth_wrap_req_encode,
0240     .crrefresh  = unx_refresh,
0241     .crvalidate = unx_validate,
0242     .crunwrap_resp  = rpcauth_unwrap_resp_decode,
0243 };