Branch data Line data Source code
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 : : 24 : : static struct rpc_auth unix_auth; 25 : : static const struct rpc_credops unix_credops; 26 : : static mempool_t *unix_pool; 27 : : 28 : : static struct rpc_auth * 29 : 0 : unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) 30 : : { 31 : 0 : refcount_inc(&unix_auth.au_count); 32 : 0 : return &unix_auth; 33 : : } 34 : : 35 : : static void 36 : 0 : unx_destroy(struct rpc_auth *auth) 37 : : { 38 : 0 : } 39 : : 40 : : /* 41 : : * Lookup AUTH_UNIX creds for current process 42 : : */ 43 : : static struct rpc_cred * 44 : 0 : unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) 45 : : { 46 : 0 : struct rpc_cred *ret = mempool_alloc(unix_pool, GFP_NOFS); 47 : : 48 : 0 : rpcauth_init_cred(ret, acred, auth, &unix_credops); 49 : 0 : ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; 50 : 0 : return ret; 51 : : } 52 : : 53 : : static void 54 : 0 : unx_free_cred_callback(struct rcu_head *head) 55 : : { 56 : 0 : struct rpc_cred *rpc_cred = container_of(head, struct rpc_cred, cr_rcu); 57 : : 58 : 0 : put_cred(rpc_cred->cr_cred); 59 : 0 : mempool_free(rpc_cred, unix_pool); 60 : 0 : } 61 : : 62 : : static void 63 : 0 : unx_destroy_cred(struct rpc_cred *cred) 64 : : { 65 : 0 : call_rcu(&cred->cr_rcu, unx_free_cred_callback); 66 : 0 : } 67 : : 68 : : /* 69 : : * Match credentials against current the auth_cred. 70 : : */ 71 : : static int 72 : 0 : unx_match(struct auth_cred *acred, struct rpc_cred *cred, int flags) 73 : : { 74 : : unsigned int groups = 0; 75 : : unsigned int i; 76 : : 77 : 0 : if (cred->cr_cred == acred->cred) 78 : : return 1; 79 : : 80 : 0 : if (!uid_eq(cred->cr_cred->fsuid, acred->cred->fsuid) || !gid_eq(cred->cr_cred->fsgid, acred->cred->fsgid)) 81 : : return 0; 82 : : 83 : 0 : if (acred->cred->group_info != NULL) 84 : 0 : groups = acred->cred->group_info->ngroups; 85 : 0 : if (groups > UNX_NGROUPS) 86 : : groups = UNX_NGROUPS; 87 : 0 : if (cred->cr_cred->group_info == NULL) 88 : 0 : return groups == 0; 89 : 0 : if (groups != cred->cr_cred->group_info->ngroups) 90 : : return 0; 91 : : 92 : 0 : for (i = 0; i < groups ; i++) 93 : 0 : 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 : : */ 102 : : static int 103 : 0 : unx_marshal(struct rpc_task *task, struct xdr_stream *xdr) 104 : : { 105 : 0 : struct rpc_clnt *clnt = task->tk_client; 106 : 0 : struct rpc_cred *cred = task->tk_rqstp->rq_cred; 107 : : __be32 *p, *cred_len, *gidarr_len; 108 : : int i; 109 : 0 : struct group_info *gi = cred->cr_cred->group_info; 110 : 0 : struct user_namespace *userns = clnt->cl_cred ? 111 : 0 : clnt->cl_cred->user_ns : &init_user_ns; 112 : : 113 : : /* Credential */ 114 : : 115 : 0 : p = xdr_reserve_space(xdr, 3 * sizeof(*p)); 116 : 0 : if (!p) 117 : : goto marshal_failed; 118 : 0 : *p++ = rpc_auth_unix; 119 : : cred_len = p++; 120 : 0 : *p++ = xdr_zero; /* stamp */ 121 : 0 : if (xdr_stream_encode_opaque(xdr, clnt->cl_nodename, 122 : 0 : clnt->cl_nodelen) < 0) 123 : : goto marshal_failed; 124 : 0 : p = xdr_reserve_space(xdr, 3 * sizeof(*p)); 125 : 0 : if (!p) 126 : : goto marshal_failed; 127 : 0 : *p++ = cpu_to_be32(from_kuid_munged(userns, cred->cr_cred->fsuid)); 128 : 0 : *p++ = cpu_to_be32(from_kgid_munged(userns, cred->cr_cred->fsgid)); 129 : : 130 : 0 : gidarr_len = p++; 131 : 0 : if (gi) 132 : 0 : for (i = 0; i < UNX_NGROUPS && i < gi->ngroups; i++) 133 : 0 : *p++ = cpu_to_be32(from_kgid_munged(userns, gi->gid[i])); 134 : 0 : *gidarr_len = cpu_to_be32(p - gidarr_len - 1); 135 : 0 : *cred_len = cpu_to_be32((p - cred_len - 1) << 2); 136 : 0 : p = xdr_reserve_space(xdr, (p - gidarr_len - 1) << 2); 137 : 0 : if (!p) 138 : : goto marshal_failed; 139 : : 140 : : /* Verifier */ 141 : : 142 : 0 : p = xdr_reserve_space(xdr, 2 * sizeof(*p)); 143 : 0 : if (!p) 144 : : goto marshal_failed; 145 : 0 : *p++ = rpc_auth_null; 146 : 0 : *p = xdr_zero; 147 : : 148 : 0 : return 0; 149 : : 150 : : marshal_failed: 151 : : return -EMSGSIZE; 152 : : } 153 : : 154 : : /* 155 : : * Refresh credentials. This is a no-op for AUTH_UNIX 156 : : */ 157 : : static int 158 : 0 : unx_refresh(struct rpc_task *task) 159 : : { 160 : 0 : set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags); 161 : 0 : return 0; 162 : : } 163 : : 164 : : static int 165 : 0 : unx_validate(struct rpc_task *task, struct xdr_stream *xdr) 166 : : { 167 : 0 : struct rpc_auth *auth = task->tk_rqstp->rq_cred->cr_auth; 168 : : __be32 *p; 169 : : u32 size; 170 : : 171 : 0 : p = xdr_inline_decode(xdr, 2 * sizeof(*p)); 172 : 0 : if (!p) 173 : : return -EIO; 174 : 0 : 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 : 0 : if (size > RPC_MAX_AUTH_SIZE) 184 : : return -EIO; 185 : 0 : p = xdr_inline_decode(xdr, size); 186 : 0 : if (!p) 187 : : return -EIO; 188 : : 189 : 0 : auth->au_verfsize = XDR_QUADLEN(size) + 2; 190 : 0 : auth->au_rslack = XDR_QUADLEN(size) + 2; 191 : 0 : auth->au_ralign = XDR_QUADLEN(size) + 2; 192 : 0 : return 0; 193 : : } 194 : : 195 : 3 : int __init rpc_init_authunix(void) 196 : : { 197 : 3 : unix_pool = mempool_create_kmalloc_pool(16, sizeof(struct rpc_cred)); 198 : 3 : return unix_pool ? 0 : -ENOMEM; 199 : : } 200 : : 201 : 0 : void rpc_destroy_authunix(void) 202 : : { 203 : 0 : mempool_destroy(unix_pool); 204 : 0 : } 205 : : 206 : : const 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 : : 215 : : static 216 : : struct 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 : : 225 : : static 226 : : const 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 : : };